PluginProbe
Spoki – Chat Buttons and WooCommerce Notifications / 2.17.4
Spoki – Chat Buttons and WooCommerce Notifications v2.17.4
2.17.4 trunk 1.0.0 2.0.0 2.0.1 2.0.10 2.0.11 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.10.0 2.11.0 2.11.1 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.14.0 All 69 releases
spoki / spoki.php

spoki.php in Spoki – Chat Buttons and WooCommerce Notifications 2.17.4, at spoki.php

1,504 lines 69.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /* @wordpress-plugin
3 * Plugin Name: Spoki - Chat Buttons and WooCommerce Notifications
4 * Description: Integrate WhatsApp on your Business! Use Spoki to recover abandoned carts, add chat buttons and send order status notifications via WhatsApp.
5 * Version: 2.17.4
6 * Author: NextAI Srl
7 * Author URI: https://spoki.com
8 * Text Domain: spoki
9 * Domain Path: /languages
10 * License: GPLv2
11 */
12
13 define('SPOKI_PLUGIN_FILE', __FILE__);
14 define('SPOKI_BASE', plugin_basename(SPOKI_PLUGIN_FILE));
15 define('SPOKI_DIR', plugin_dir_path(SPOKI_PLUGIN_FILE));
16 define('SPOKI_URL', plugins_url('/', SPOKI_PLUGIN_FILE));
17 define('SPOKI_SETTING_TABLE', 'spoki_setting');
18 define('SPOKI_ABANDONMENT_TABLE', 'spoki_abandonment');
19
20 include_once SPOKI_DIR . 'includes/constants.php';
21 include_once SPOKI_DIR . 'includes/spoki-functions.php';
22 include_once SPOKI_DIR . 'modules/abandoned-carts/spoki-abandoned-carts.php';
23
24 add_filter('cron_schedules', 'add_cron_interval');
25 add_filter('http_request_timeout', 'extend_http_request_timeout');
26
27 function add_cron_interval($schedules)
28 {
29 $schedules['every_day'] = array(
30 'interval' => 86400,
31 'display' => esc_html__('Every day'),);
32 return $schedules;
33 }
34
35
36 function extend_http_request_timeout($timeout)
37 {
38 return 30; // seconds
39 }
40
41 add_action('plugins_loaded', function () {
42 /** Init Spoki */
43 Spoki();
44 }, 9);
45
46
47 function Spoki()
48 {
49 return WpSpoki::instance();
50 }
51
52 final class WpSpoki
53 {
54 protected static $_instance = null;
55 public string $version = '';
56 private string $langs = '';
57 public array $shop = [];
58 public array $options = [];
59
60 public $api_plan = SPOKI_BASE_API . "plan/";
61 public $api_status = SPOKI_BASE_API . "status/";
62 public $api_enable_flex = SPOKI_BASE_API . "enable/";
63 public $api_account = SPOKI_BASE_API . "account/";
64
65 public static function instance()
66 {
67 if (is_null(self::$_instance)) {
68 self::$_instance = new self();
69 }
70 return self::$_instance;
71 }
72
73 private function __construct()
74 {
75 $data = get_file_data(__FILE__, array('ver' => 'Version', 'langs' => 'Domain Path'));
76 $this->version = $data['ver'];
77 $this->langs = $data['langs'];
78 $this->options = get_option(SPOKI_OPTIONS) ? get_option(SPOKI_OPTIONS) : [];
79
80 $has_fixed_support_button = isset($this->options['buttons']['fixed_support_button_check']) && $this->options['buttons']['fixed_support_button_check'] == 1;
81 $has_product_item_listing_button = isset($this->options['woocommerce']['product_item_listing_button_check']) && $this->options['woocommerce']['product_item_listing_button_check'] == 1;
82 $has_cart_button = isset($this->options['woocommerce']['cart_button_check']) && $this->options['woocommerce']['cart_button_check'] == 1;
83 $has_single_product_button = isset($this->options['woocommerce']['single_product_button_check']) && $this->options['woocommerce']['single_product_button_check'] == 1;
84 $has_abandoned_carts = isset($this->options['abandoned_carts']['enable_tracking']) && $this->options['abandoned_carts']['enable_tracking'] == 1;
85 $has_order_updated_notification = (isset($this->options['woocommerce']['order_updated']) && $this->options['woocommerce']['order_updated'] == 1);
86 $has_order_created_notification = (isset($this->options['woocommerce']['order_created']) && $this->options['woocommerce']['order_created'] == 1);
87 $has_order_deleted_notification = (isset($this->options['woocommerce']['order_deleted']) && $this->options['woocommerce']['order_deleted'] == 1);
88 $has_order_note_added_notification = (isset($this->options['woocommerce']['order_note_added']) && $this->options['woocommerce']['order_note_added'] == 1);
89 $has_leave_review_notification = (isset($this->options['woocommerce']['leave_review']) && $this->options['woocommerce']['leave_review'] == 1);
90 $has_notifications = (
91 $has_order_updated_notification ||
92 $has_order_created_notification ||
93 $has_order_deleted_notification ||
94 $has_order_note_added_notification ||
95 $has_leave_review_notification
96 );
97 $has_order_created_to_seller_notification = (isset($this->options['woocommerce']['order_created_to_seller']) && $this->options['woocommerce']['order_created_to_seller'] == 1);
98 $has_cart_recovered_to_seller_notification = (isset($this->options['abandoned_carts']['notify_to_admin']) && $this->options['abandoned_carts']['notify_to_admin'] == 1);
99 $is_auto_update_disabled = (isset($this->options['disable_auto_update']) && $this->options['disable_auto_update'] == 1);
100 $abandoned_carts_waiting_minutes = (isset($this->options['abandoned_carts']['waiting_minutes'])) ? intval($this->options['abandoned_carts']['waiting_minutes']) : 15;
101
102 $this->shop = [
103 "plugin_version" => $this->version,
104 "name" => $this->options['shop_name'] ?? get_bloginfo('name'),
105 "url" => get_bloginfo('url'),
106 "email" => $this->options['email'] ?? get_bloginfo('admin_email'),
107 "language" => $this->options['language'] ?? get_bloginfo('language'),
108 "telephone" => ($this->options['prefix'] ?? '') . ($this->options['telephone'] ?? ''),
109 "contact_link" => isset($this->options['contact_link']) ? $this->options['contact_link'] : null,
110 "default_prefix" => isset($this->options['default_prefix']) ? $this->options['default_prefix'] : null,
111 "has_fixed_support_button" => $has_fixed_support_button,
112 "has_product_item_listing_button" => $has_product_item_listing_button,
113 "has_cart_button" => $has_cart_button,
114 "has_single_product_button" => $has_single_product_button,
115 "has_abandoned_carts" => $has_abandoned_carts,
116 "has_order_updated_notification" => $has_order_updated_notification,
117 "has_order_created_notification" => $has_order_created_notification,
118 "has_order_deleted_notification" => $has_order_deleted_notification,
119 "has_order_note_added_notification" => $has_order_note_added_notification,
120 "has_leave_review_notification" => $has_leave_review_notification,
121 "has_notifications" => $has_notifications,
122 "has_order_created_to_seller_notification" => $has_order_created_to_seller_notification,
123 "has_cart_recovered_to_seller_notification" => $has_cart_recovered_to_seller_notification,
124 "abandoned_carts_waiting_minutes" => $abandoned_carts_waiting_minutes,
125 "is_auto_update_disabled" => $is_auto_update_disabled,
126 ];
127
128 register_activation_hook(SPOKI_PLUGIN_FILE, array($this, 'activation_reset'));
129 register_deactivation_hook(SPOKI_PLUGIN_FILE, array($this, 'deactivation_reset'));
130
131 add_action('init', 'spoki_update_po_file');
132 add_action('admin_menu', array($this, 'add_option_menu'));
133 add_action('admin_menu', array($this, 'add_submenu'), 99);
134 add_filter("plugin_action_links_" . plugin_basename(__FILE__), array($this, 'plugin_settings_link'));
135 add_action('wp_enqueue_scripts', array($this, 'add_styles'));
136 add_action('admin_enqueue_scripts', array($this, 'add_admin_styles'));
137 add_action('admin_enqueue_scripts', array($this, 'add_admin_scripts'));
138 add_action('updated_option', array($this, 'on_option_added'), 10, 3);
139 add_filter('auto_update_plugin', array($this, 'auto_update_plugin'), 10, 2);
140 add_action('spoki_cron_hook', array($this, 'check_secret_status'));
141 if (!wp_next_scheduled('spoki_cron_hook')) {
142 $this->check_secret_status();
143 wp_schedule_event(time(), 'every_day', 'spoki_cron_hook');
144 }
145
146 $this->includes();
147 $this->render_buttons();
148 $this->handle_woocommerce();
149 $this->handle_abandoned_carts();
150
151 add_action('elementor/widgets/widgets_registered', array($this, 'register_elementor_widgets'));
152
153 }
154
155 /**
156 * Include all Spoki required files
157 */
158 private function includes()
159 {
160 require_once SPOKI_DIR . 'includes/spoki-functions.php';
161 }
162
163 /**
164 * Get the setting link of the plugin
165 *
166 * @param $links
167 * @return mixed
168 */
169 public function plugin_settings_link($links)
170 {
171 $settings_link = '<a href="admin.php?page=' . SPOKI_PLUGIN_NAME . '">' . __('Settings', SPOKI_PLUGIN_NAME) . '</a>';
172 array_unshift($links, $settings_link);
173 return $links;
174 }
175
176 /**
177 * Add the Spoki option to the menu
178 */
179 public function add_option_menu()
180 {
181 add_menu_page(
182 'Spoki Options',
183 "Spoki",
184 'manage_options',
185 'spoki',
186 array($this, 'render_setup_page'),
187 plugins_url() . '/' . SPOKI_PLUGIN_NAME . '/assets/images/logo.svg',
188 98
189 );
190 add_action('admin_init', array($this, 'register_option_var'));
191 }
192
193 /**
194 * Add the Spoki option submenu
195 */
196 function add_submenu()
197 {
198 $has_woocommerce = ('woocommerce/woocommerce.php');
199 $is_pro = isset($this->options['account_info']['plan']['is_pro']) && $this->options['account_info']['plan']['is_pro'] == true;
200
201 add_submenu_page('spoki', __('Statistics', "spoki"), __('Statistics', "spoki"), 'manage_options', "admin.php?page=" . SPOKI_PLUGIN_NAME . "&tab=welcome");
202 add_submenu_page('spoki', __('Buttons', "spoki"), __('Buttons', "spoki"), 'manage_options', "admin.php?page=" . SPOKI_PLUGIN_NAME . "&tab=buttons");
203 add_submenu_page('spoki', __('Customer Notifications', "spoki"), __('Customer Notifications', "spoki"), 'manage_options', "admin.php?page=" . SPOKI_PLUGIN_NAME . "&tab=customer-notifications");
204 add_submenu_page('spoki', __('Seller Notifications', "spoki"), __('Seller Notifications', "spoki"), 'manage_options', "admin.php?page=" . SPOKI_PLUGIN_NAME . "&tab=seller-notifications");
205 add_submenu_page('spoki', __('Abandoned Carts', "spoki"), __('Abandoned Carts', "spoki"), 'manage_options', "admin.php?page=" . SPOKI_PLUGIN_NAME . "&tab=abandoned-carts");
206 add_submenu_page('spoki', __('Settings', "spoki"), __('Settings', "spoki"), 'manage_options', "admin.php?page=" . SPOKI_PLUGIN_NAME . "&tab=settings");
207 if (!$is_pro) {
208 add_submenu_page('spoki', __('Upgrade', "spoki"), "<span class='color-spoki text-bold'>⇡ " . __('Upgrade', "spoki") . "</span>", 'manage_options', $this->get_pro_plan_link());
209 }
210
211 if ($has_woocommerce) {
212 add_submenu_page(
213 'woocommerce',
214 __('Spoki', "spoki"),
215 __('Spoki', "spoki"),
216 'manage_options',
217 "admin.php?page=" . SPOKI_PLUGIN_NAME . "&tab=welcome",
218 null,
219 8
220 );
221 }
222
223 }
224
225 /**
226 * Register the Spoki option
227 */
228 public function register_option_var()
229 {
230 register_setting('wp-spoki-option', SPOKI_OPTIONS);
231 }
232
233 /**
234 * Add website spoki styles
235 */
236 public function add_styles()
237 {
238 $styles = ['buttons'];
239 foreach ($styles as $style) {
240 echo "<style id='spoki-style-$style'>";
241 include SPOKI_DIR . "assets/css/$style.css";
242 echo "</style>";
243 }
244 }
245
246 /**
247 * Add admin spoki styles
248 */
249 public function add_admin_styles()
250 {
251 $styles = ['admin.css', 'onboarding.css', 'account-overview.css', 'spoki-overview.css'];
252
253 foreach ($styles as $style) {
254 echo "<style>";
255 include_once SPOKI_DIR . 'assets/css/' . $style;
256 echo "</style>";
257 }
258
259 $this->add_styles();
260 }
261
262 /**
263 * Add admin spoki scripts
264 */
265 public function add_admin_scripts()
266 {
267 $scripts = ['spoki-admin.js', 'spoki-shadowed-buttons.js'];
268
269 foreach ($scripts as $script) {
270 echo "<script>";
271 include_once SPOKI_DIR . 'assets/js/' . $script;
272 echo "</script>";
273 }
274 }
275
276 /**
277 * Enable plugin autoupdate
278 */
279 function auto_update_plugin($update, $item)
280 {
281 $plugins = array('spoki');
282 $is_auto_update_disabled = (isset($this->options['disable_auto_update']) && $this->options['disable_auto_update'] == 1);
283 if (in_array($item->slug, $plugins) && !$is_auto_update_disabled)
284 return true;
285 else return $update;
286 }
287
288 /**
289 * Register widgets for Elementor
290 */
291 public function register_elementor_widgets()
292 {
293 if (spoki_has_elementor()) {
294 include_once SPOKI_DIR . 'widgets/class-elementor-spoki-button.php';
295 \Elementor\Plugin::instance()->widgets_manager->register_widget_type(new \Elementor_Spoki_Button_Widget());
296 }
297 }
298
299 /**
300 * Handle option submit
301 *
302 * @param $option
303 * @param $old_value
304 * @param $value
305 */
306 public function on_option_added($option, $old_value, $value)
307 {
308 if ($option == SPOKI_OPTIONS) {
309
310 /** Onboarding Without WooCommerce */
311 if (isset($value['onboarding']['without_wc'])) {
312 $this->update_options($value, [
313 "telephone" => $value['onboarding']['telephone'],
314 "prefix" => $value['onboarding']['prefix'],
315 "onboarding" => null,
316 ]);
317 $url = admin_url('/admin.php?page=' . SPOKI_PLUGIN_NAME . '&tab=buttons');
318 header("Location: {$url}");
319 exit;
320 }
321
322 /** Onboarding With WooCommerce */
323
324 if (isset($value['onboarding']['with_wc'])) {
325 $response = array(
326 "secret" => $value['onboarding']['spoki_onboarding_secret'],
327 "delivery_url" => $value['onboarding']['spoki_onboarding_delivery_url'],
328 );
329 if (isset($response['secret']) && isset($response['delivery_url'])) {
330 $this->update_options($value, [
331 "telephone" => $value['onboarding']['telephone'],
332 "prefix" => $value['onboarding']['prefix'],
333 "email" => $value['onboarding']['email'],
334 "shop_name" => $value['onboarding']['shop_name'],
335 "secret" => $response['secret'],
336 "delivery_url" => $response['delivery_url'],
337 "onboarding" => null,
338 "woocommerce" => [
339 "order_created" => 0,
340 "order_updated" => 0,
341 "order_deleted" => 0,
342 "order_note_added" => 0,
343 "leave_review" => 0,
344 "leave_review_days" => 5,
345 "order_created_to_seller" => 0,
346 ],
347 "abandoned_carts" => [
348 "enable_tracking" => 0,
349 "notify_to_admin" => 0,
350 ],
351 "secret_status" => [
352 'secret' => $response['secret'],
353 'delivery_url' => $response['delivery_url'],
354 'code' => 200,
355 'message' => ''
356 ]
357 ]);
358 $url = admin_url('/admin.php?page=' . SPOKI_PLUGIN_NAME . '&tab=customer-notifications');
359 header("Location: {$url}");
360 exit;
361 }
362 }
363
364 if (isset($value['account_info']['response_json'])) {
365 $account_info = json_decode($value['account_info']['response_json'] ?? '{}', true);
366 if ($account_info) {
367 $this->update_options(get_option(SPOKI_OPTIONS), ["account_info" => $account_info]);
368 }
369 }
370
371 /** Settings updated for registered account */
372 if (isset($value['is_settings'])) {
373 $keys_changed = ($value['secret'] != $old_value['secret']) || ($value['delivery_url'] != $old_value['delivery_url']);
374 if ($keys_changed) {
375 $url = admin_url('/admin.php?page=' . SPOKI_PLUGIN_NAME . '&tab=welcome');
376 header("Location: {$url}");
377 exit;
378 }
379 }
380
381 /** Enable all notifications from dashboard */
382 if (isset($value['enable_notifications']) && $value['enable_notifications'] == 1) {
383 $this->update_options(get_option(SPOKI_OPTIONS), [
384 "enable_notifications" => 0,
385 "woocommerce" => [
386 "order_created" => 1,
387 "order_updated" => 1,
388 "order_deleted" => 1,
389 "order_note_added" => 1,
390 "leave_review" => 1,
391 "leave_review_days" => 5,
392 ]
393 ]);
394 $url = admin_url('/admin.php?page=' . SPOKI_PLUGIN_NAME . '&tab=customer-notifications');
395 header("Location: {$url}");
396 exit;
397 }
398
399 /** Enable order status notifications from dashboard */
400 if (isset($value['enable_order_status_notifications']) && $value['enable_order_status_notifications'] == 1) {
401 $this->update_options(get_option(SPOKI_OPTIONS), [
402 "enable_order_status_notifications" => 0,
403 "woocommerce" => [
404 "order_created" => 1,
405 "order_updated" => 1,
406 "order_deleted" => 1,
407 ]
408 ]);
409 $url = admin_url('/admin.php?page=' . SPOKI_PLUGIN_NAME . '&tab=customer-notifications');
410 header("Location: {$url}");
411 exit;
412 }
413
414 /** Enable seller notifications from dashboard */
415 if (isset($value['enable_seller_notifications']) && $value['enable_seller_notifications'] == 1) {
416 $this->update_options(get_option(SPOKI_OPTIONS), [
417 "enable_seller_notifications" => 0,
418 "woocommerce" => [
419 "order_created_to_seller" => 1,
420 ]
421 ]);
422 $url = admin_url('/admin.php?page=' . SPOKI_PLUGIN_NAME . '&tab=seller-notifications');
423 header("Location: {$url}");
424 exit;
425 }
426
427 /** Enable leave review notification from dashboard */
428 if (isset($value['enable_leave_review_notification']) && $value['enable_leave_review_notification'] == 1) {
429 $this->update_options(get_option(SPOKI_OPTIONS), [
430 "enable_leave_review_notification" => 0,
431 "woocommerce" => [
432 "leave_review" => 1,
433 "leave_review_days" => 5,
434 ]
435 ]);
436 $url = admin_url('/admin.php?page=' . SPOKI_PLUGIN_NAME . '&tab=customer-notifications');
437 header("Location: {$url}");
438 exit;
439 }
440
441 /** Enable enable order note added notification from dashboard */
442 if (isset($value['enable_order_note_added_notification']) && $value['enable_order_note_added_notification'] == 1) {
443 $this->update_options(get_option(SPOKI_OPTIONS), [
444 "enable_order_note_added_notification" => 0,
445 "woocommerce" => [
446 "order_note_added" => 1,
447 ]
448 ]);
449 $url = admin_url('/admin.php?page=' . SPOKI_PLUGIN_NAME . '&tab=customer-notifications');
450 header("Location: {$url}");
451 exit;
452 }
453 }
454 }
455
456 /**
457 * Handle WooCommerce features
458 */
459 public function handle_woocommerce()
460 {
461 if (isset($this->options['secret'])) {
462 include_once(ABSPATH . 'wp-admin/includes/plugin.php');
463 if (spoki_has_woocommerce()) {
464 add_action('woocommerce_checkout_update_order_meta', array($this, 'send_woocommerce_order_created_alert'), 1, 3);
465 add_action('woocommerce_order_status_changed', array($this, 'send_woocommerce_order_created_or_updated_alert'), 1, 3);
466 add_action('woocommerce_cancelled_order', array($this, 'send_woocommerce_order_deleted_alert'), 10, 3);
467 add_action('woocommerce_trash_order', array($this, 'send_woocommerce_order_deleted_alert'), 10, 3);
468 add_action('woocommerce_order_note_added', array($this, 'send_woocommerce_note_alert'), 10, 2);
469 add_action('woocommerce_order_status_completed', array($this, 'send_woocommerce_review_alert'), 10, 2);
470
471 if (isset($this->options['woocommerce']['cart_button_hide_checkout_button_check']) && $this->options['woocommerce']['cart_button_hide_checkout_button_check'] == 1) {
472 add_action('woocommerce_proceed_to_checkout', array($this, 'disable_checkout_button'), 1);
473 }
474 }
475 }
476 }
477
478 /**
479 * Handle WooCommerce abandoned carts feature
480 */
481 public function handle_abandoned_carts()
482 {
483 $Abandonment = Spoki_Abandoned_Carts::instance();
484 if (isset($this->options['abandoned_carts']['enable_tracking']) && $this->options['abandoned_carts']['enable_tracking'] == 1) {
485 $this->initialize_cart_abandonment_tables();
486 do_action('spoki_cartflow_ca_init');
487 } elseif (wp_next_scheduled('spoki_abandoned_carts_cron_hook')) {
488 # Unschedule hook for versions <= v2.8.1
489 $Abandonment->unschedule_hook();
490 }
491 }
492
493 /**
494 * Create new database tables for plugin updates.
495 *
496 * @return void
497 */
498 public function initialize_cart_abandonment_tables()
499 {
500 include_once SPOKI_DIR . 'modules/abandoned-carts/spoki-abandoned-carts-db.php';
501 $db = Spoki_Abandoned_Carts_Db::instance();
502 $db->create_tables();
503 $db->init_tables();
504 }
505
506 /**
507 * Send the Spoki notification for order status created or updated
508 *
509 * @param $order_get_id
510 * @param $from
511 * @param $to
512 */
513 public function send_woocommerce_order_created_alert($order_get_id)
514 {
515 $this->send_woocommerce_order_alert($order_get_id, 'order.updated');
516 }
517
518 /**
519 * Send the Spoki notification for order status created or updated
520 *
521 * @param $order_get_id
522 * @param $from
523 * @param $to
524 */
525 public function send_woocommerce_order_created_or_updated_alert($order_get_id, $from, $to)
526 {
527 $this->send_woocommerce_order_alert($order_get_id, 'order.updated', ["from_status" => $from, "to_status" => $to]);
528 }
529
530 /**
531 * Send the Spoki notification for review
532 *
533 * @param $order_get_id
534 */
535 public function send_woocommerce_review_alert($order_get_id)
536 {
537 $review_link = (isset($this->options['woocommerce']['leave_review_link']) && $this->options['woocommerce']['leave_review_link'] != "") ? $this->options['woocommerce']['leave_review_link'] : "";
538 $review_link_days = (isset($this->options['woocommerce']['leave_review_days']) && $this->options['woocommerce']['leave_review_days'] != "") ? $this->options['woocommerce']['leave_review_days'] : 5;
539 $this->send_woocommerce_order_alert($order_get_id, 'order.review', ["review_link" => $review_link, "delay" => intval($review_link_days) * 24 * 60 * 60]);
540 }
541
542 /**
543 * Notify the Abandoned Cart Info Spoki notification
544 *
545 * @param $session_id
546 * @param $checkoutDetails
547 * @param $topic
548 * @return bool
549 */
550 public function notify_abandoned_cart_info($session_id, $checkoutDetails, $topic): bool
551 {
552 $other_fields = unserialize($checkoutDetails->other_fields);
553 $parts = explode(',', $other_fields['spoki_location']);
554 $country = $parts[0];
555
556 $phone = trim(sanitize_text_field($other_fields['spoki_phone_number']));
557 if ($phone != '' && $phone[0] != '+') {
558 $default_prefix = isset($this->options['default_prefix']) ? $this->options['default_prefix'] : '';
559 $phone = $default_prefix . $phone;
560 }
561
562 $checkout_base_url = (isset($this->options['custom_checkout_url']) && $this->options['custom_checkout_url'] != "") ? $this->options['custom_checkout_url'] : wc_get_page_permalink('checkout');
563 $custom_checkout_session_id_param = (isset($this->options['custom_checkout_session_id_param']) && $this->options['custom_checkout_session_id_param'] != "") ? $this->options['custom_checkout_session_id_param'] : "session_id";
564
565 $cart_contents = unserialize($checkoutDetails->cart_contents);
566 $products = [];
567 $products_context = [];
568
569 if (is_array($cart_contents)) {
570 foreach ($cart_contents as $cart_item) {
571 $product = isset($cart_item['data']) && is_object($cart_item['data']) && method_exists($cart_item['data'], 'get_name')
572 ? $cart_item['data']
573 : (isset($cart_item['product_id']) ? wc_get_product($cart_item['product_id']) : null);
574
575 if (!$product) {
576 continue;
577 }
578
579 $image_id = $product->get_image_id();
580 $products[] = [
581 'title' => $product->get_name(),
582 'name' => $product->get_name(),
583 'quantity' => isset($cart_item['quantity']) ? $cart_item['quantity'] : 1,
584 'image' => $image_id ? (wp_get_attachment_image_url($image_id, 'medium') ?: '') : '',
585 ];
586 }
587 }
588
589 // Create WOO_PRODUCTS string
590 $products_list = [];
591 foreach ($products as $product) {
592 $products_list[] = ($product['title'] ?: '--') . ' x' . ($product['quantity'] ?: '1');
593 }
594 $products_context['%%WOO_PRODUCTS%%'] = implode(', ', $products_list);
595
596 // Create individual product variables (WOO_PRODUCT_1_TITLE, etc.)
597 for ($i = 1; $i <= 10; $i++) {
598 if ($i <= count($products)) {
599 $product = $products[$i - 1];
600 $products_context["%%WOO_PRODUCT_{$i}_TITLE%%"] = ($product['title'] ?: '--') . ' x' . ($product['quantity'] ?: '1');
601 $products_context["%%WOO_PRODUCT_{$i}_IMAGE%%"] = $product['image'] ?: '';
602 } else {
603 $products_context["%%WOO_PRODUCT_{$i}_TITLE%%"] = '';
604 $products_context["%%WOO_PRODUCT_{$i}_IMAGE%%"] = '';
605 }
606 }
607
608 $data = [
609 "customer" => [
610 'email' => $checkoutDetails->email,
611 'phone' => $phone,
612 'country' => sanitize_text_field($country),
613 'first_name' => sanitize_text_field($other_fields['spoki_first_name']),
614 'last_name' => sanitize_text_field($other_fields['spoki_last_name']),
615 'name' => sanitize_text_field($other_fields['spoki_first_name']) . ' ' . sanitize_text_field($other_fields['spoki_last_name']),
616 ],
617 "checkout" => [
618 "checkout_url" => $checkout_base_url . '?' . $custom_checkout_session_id_param . '=' . $checkoutDetails->session_id,
619 "checkout_info" => $other_fields,
620 "cart_contacted_url" => get_bloginfo('url') . '/wp-json/api/v1/setCartAsContacted',
621 "total" => $checkoutDetails->cart_total,
622 "currency" => get_woocommerce_currency(),
623 "products" => $products,
624 "products_context" => $products_context,
625 ],
626 "session_id" => $session_id,
627 ];
628 return $this->spoki_send($data, $topic);
629 }
630
631 /**
632 * Send the Spoki notification for order deleted
633 *
634 * @param $order_get_id
635 */
636 public function send_woocommerce_order_deleted_alert($order_get_id)
637 {
638 $this->send_woocommerce_order_alert($order_get_id, 'order.deleted');
639 }
640
641 /**
642 * Send the Spoki notification for order status
643 *
644 * @param $order_get_id
645 * @param $topic
646 * @param $additional_data
647 */
648 public function send_woocommerce_order_alert($order_get_id, $topic, $additional_data = [])
649 {
650 $order = wc_get_order($order_get_id);
651
652 // Session Handling
653 $session = [];
654 try {
655 $session_id = WC()->session ? WC()->session->get('spoki_session_id') : null;
656 if (!$session_id && $this->shop['has_abandoned_carts']) {
657 $spoki_abandoned_carts = Spoki_Abandoned_Carts::instance();
658 $checkout = $spoki_abandoned_carts->get_order_checkout_details($order_get_id);
659 if ($checkout) {
660 $other_fields = unserialize($checkout->other_fields);
661 $session_id = $other_fields['spoki_session_id'] ?? null;
662 }
663 }
664 if ($session_id) {
665 $session = ['session_id' => $session_id];
666 }
667 } catch (\Throwable $e) {
668 // Can't set session_id
669 }
670
671 $order_data = array_merge(((isset($order) && false != $order ? $order->get_data() : ["id" => $order_get_id])), $additional_data);
672 // Add order_number (can be different from ID if using sequential order number plugins)
673 if (isset($order) && false != $order) {
674 $order_data['order_number'] = $order->get_order_number();
675 }
676 if (!isset($order_data["to_status"])) {
677 $order_data["from_status"] = $order_data["status"];
678 $order_data["to_status"] = $order_data["status"];
679 }
680
681 $parts = explode(',', isset($order_data['billing']['country']) ? $order_data['billing']['country'] : '');
682 $country = $parts[0];
683 $phone = trim(isset($order_data['billing']['phone']) ? $order_data['billing']['phone'] : '');
684 if ($phone != '' && $phone[0] != '+') {
685 $default_prefix = isset($this->options['default_prefix']) ? $this->options['default_prefix'] : '';
686 $phone = $default_prefix . $phone;
687 }
688 $customer = [
689 'email' => isset($order_data['billing']['email']) ? $order_data['billing']['email'] : '',
690 'phone' => $phone,
691 'country' => $country ?? '',
692 'first_name' => (isset($order_data['billing']['first_name']) ? $order_data['billing']['first_name'] : ''),
693 'last_name' => (isset($order_data['billing']['last_name']) ? $order_data['billing']['last_name'] : ''),
694 'name' => (isset($order_data['billing']['first_name']) ? $order_data['billing']['first_name'] : '') . ' ' . (isset($order_data['billing']['last_name']) ? $order_data['billing']['last_name'] : ''),
695 ];
696 $this->spoki_send(array_merge([
697 "order" => $order_data,
698 "customer" => $customer,
699 ], $session), $topic);
700 }
701
702 /**
703 * Send the Spoki notification for tracking number
704 *
705 * @param $id
706 * @param $order
707 */
708 public function send_woocommerce_note_alert($id, $order)
709 {
710 $comment = get_comment($id);
711 if (isset($comment->comment_content)) {
712 $is_gls_tracking = substr(strtolower($comment->comment_content), 0, 4) == '[gls';
713 $is_user_tracking = substr(strtolower($comment->comment_content), 0, 10) == '[tracking]';
714
715 /** Send the message only if it is a tracking order note */
716 if ($comment->comment_type == 'order_note' && ($is_gls_tracking || $is_user_tracking)) {
717 $order_data = $order->get_data();
718 $this->send_woocommerce_order_alert($order_data['id'], 'order.tracking', ["note" => $comment]);
719 }
720 }
721 }
722
723 /**
724 * Send the Spoki notification
725 *
726 * @param $data
727 * @return bool
728 */
729 public function spoki_send($data, $topic): bool
730 {
731 $shop = ["shop" => $this->shop];
732
733 $request_params = array(
734 "headers" => array(
735 "Authorization" => $this->options['secret'],
736 "language" => $this->shop['language'],
737 "X-Wc-Webhook-Topic" => $topic,
738 ),
739 "body" => wp_json_encode(array_merge($data, $shop)),
740 "sslverify" => false,
741 "timeout" => 60,
742 );
743
744 $url = $this->options['delivery_url'];
745 $response = wp_remote_post($url, $request_params);
746 $code = wp_remote_retrieve_response_code($response);
747 return $code == 200;
748 }
749
750 /**
751 * Fetch and update the account_info
752 */
753 public function fetch_account_info()
754 {
755 $request_params = [
756 "headers" => [
757 "Authorization" => $this->options['secret'],
758 "language" => $this->shop['language']
759 ],
760 "sslverify" => false,
761 "timeout" => 60,
762 ];
763 $response = wp_remote_get($this->api_plan, $request_params);
764 $account_info = json_decode(wp_remote_retrieve_body($response), true);
765 $this->update_options(get_option(SPOKI_OPTIONS), ["account_info" => $account_info]);
766 return $account_info;
767 }
768
769 /**
770 * Check the status of the spoki keys
771 *
772 * @return array|WP_Error
773 */
774 public function check_spoki_status()
775 {
776 $secret = $this->options['secret'] ?? null;
777 $has_woocommerce = spoki_has_woocommerce();
778
779 $body = [
780 "is_plugin_active" => true,
781 "plugin_version" => $this->version,
782 "url" => $this->shop['url'],
783 "name" => $this->shop['name'],
784 "language" => $this->shop['language'],
785 "email" => $this->shop['email'],
786 "telephone" => $this->shop['telephone'],
787 "has_woocommerce" => $has_woocommerce,
788 "is_widget_fixed_enabled" => $this->shop['has_fixed_support_button'],
789 "is_widget_woo_shop_enabled" => $this->shop['has_product_item_listing_button'],
790 "is_widget_woo_item_enabled" => $this->shop['has_single_product_button'],
791 "is_widget_woo_cart_enabled" => $this->shop['has_cart_button'],
792 "is_widget_woo_checkout_enabled" => $this->shop['has_cart_button'],
793 "is_abandoned_carts_enabled" => $this->shop['has_abandoned_carts'],
794 "is_woo_send_enabled" => $has_woocommerce && $this->shop['has_notifications'],
795 "is_order_updated_notification_enabled" => $this->shop['has_order_updated_notification'],
796 "is_order_created_notification_enabled" => $this->shop['has_order_created_notification'],
797 "is_order_deleted_notification_enabled" => $this->shop['has_order_deleted_notification'],
798 "is_order_note_added_notification_enabled" => $this->shop['has_order_note_added_notification'],
799 "is_leave_review_notification_enabled" => $this->shop['has_leave_review_notification'],
800 "has_cart_recovered_to_seller_notification" => $this->shop['has_cart_recovered_to_seller_notification'],
801 "contact_link" => $this->shop['contact_link'] ?? '',
802 "default_prefix" => $this->shop['default_prefix'] ?? '',
803 ];
804
805 if ($this->shop['has_abandoned_carts']) {
806 $spoki_abandoned_carts = Spoki_Abandoned_Carts::instance();
807 $abandoned_report = $spoki_abandoned_carts->get_report_by_type(SPOKI_CART_ABANDONED_ORDER);
808 $recovered_report = $spoki_abandoned_carts->get_report_by_type(SPOKI_CART_COMPLETED_ORDER);
809 $body["abandoned_carts_reports"] = [
810 "abandoned" => $abandoned_report,
811 "recovered" => $recovered_report,
812 ];
813 }
814
815 $request_params = [
816 "headers" => [
817 "Authorization" => $secret,
818 "language" => $this->shop['language'],
819 ],
820 "body" => $body,
821 "sslverify" => false,
822 "timeout" => 60,
823 ];
824 return wp_remote_post($this->api_status, $request_params);
825 }
826
827 /**
828 * Render the admin setup page
829 */
830 public function render_setup_page()
831 {
832 require_once SPOKI_DIR . 'includes/page-setup.php';
833 $this->render_components();
834 }
835
836
837 /**
838 * Render the Spoki Components
839 */
840 public function render_components()
841 {
842 $components = ['abandoned-carts-info-dialog', 'customer-notifications-info-dialog', 'buttons-info-dialog'];
843 foreach ($components as $component) {
844 include_once SPOKI_DIR . "components/$component.php";
845 }
846 }
847
848 /**
849 * Render the WhatsApp buttons in the website
850 */
851 public function render_buttons()
852 {
853 $has_fixed_support_button = isset($this->options['buttons']['fixed_support_button_check']) && $this->options['buttons']['fixed_support_button_check'] == 1;
854 $has_product_item_listing_button = isset($this->options['woocommerce']['product_item_listing_button_check']) && $this->options['woocommerce']['product_item_listing_button_check'] == 1;
855 $has_cart_button = isset($this->options['woocommerce']['cart_button_check']) && $this->options['woocommerce']['cart_button_check'] == 1;
856 $has_single_product_button = isset($this->options['woocommerce']['single_product_button_check']) && $this->options['woocommerce']['single_product_button_check'] == 1;
857
858 // Floating Button
859 if ($has_fixed_support_button) {
860 add_action('wp_footer', array($this, 'render_floating_button'), 1);
861 }
862
863 // Product Item Listing Button
864 if ($has_product_item_listing_button) {
865 add_action('woocommerce_after_shop_loop_item', array($this, 'render_product_item_listing_button'), 99);
866 }
867
868 // Cart Page Button
869 if ($has_cart_button) {
870 add_action('woocommerce_after_cart_totals', array($this, 'render_cart_button'), 99);
871 }
872
873 // Single Product Page Button
874 if ($has_single_product_button) {
875 $position = isset($this->options['woocommerce']['single_product_button_position']) ? $this->options['woocommerce']['single_product_button_position'] : 'after_atc';
876 switch ($position) {
877 case 'under_atc':
878 add_action('woocommerce_after_add_to_cart_form', array($this, 'render_single_product_button'), 99);
879 break;
880 case 'after_shortdesc':
881 add_action('woocommerce_before_add_to_cart_form', array($this, 'render_single_product_button'), 99);
882 break;
883 case 'after_atc':
884 default:
885 add_action('woocommerce_after_add_to_cart_button', array($this, 'render_single_product_button'), 99);
886 break;
887 }
888 }
889
890 /**
891 * Render the spoki button wherever you want using the shortcode
892 * @param $attrs
893 * @param null $content
894 */
895 function spoki_button_shortcode($attrs, $content = null)
896 {
897 $hide_non_working = isset($attrs['hide_non_working']) ? sanitize_text_field($attrs['hide_non_working']) : '';
898 $working_days_times_options = Spoki()->options['working_days_times'];
899 $is_working_days_times_enabled = isset($working_days_times_options['enabled']) && $working_days_times_options['enabled'] == 1;
900 $is_non_working_day_time = spoki_is_non_working_day_time($working_days_times_options);
901 if ($hide_non_working && $is_working_days_times_enabled && $is_non_working_day_time) {
902 return;
903 }
904
905 $phone = isset($attrs['phone']) ? sanitize_text_field($attrs['phone']) : Spoki()->shop['telephone'];
906 $cta = isset($attrs['cta']) ? sanitize_text_field($attrs['cta']) : '';
907 $title = isset($attrs['title']) ? sanitize_text_field($attrs['title']) : '';
908
909 $message = isset($attrs['message']) ? sanitize_text_field($attrs['message']) : '';
910 $non_working_message = isset($attrs['non_working_message']) ? sanitize_text_field($attrs['non_working_message']) : '';
911 $is_non_working_days_times_text_enabled = isset($attrs['enable_non_working_message']) ? sanitize_text_field($attrs['enable_non_working_message']) : '';
912
913 $final_message = $message;
914 if ($is_non_working_day_time && $is_non_working_days_times_text_enabled == 1) {
915 $final_message = $non_working_message;
916 }
917
918 $additional_class = isset($attrs['additional_class']) ? sanitize_html_class($attrs['additional_class']) : '';
919 $type = 5;
920 $color = isset($attrs['color']) ? sanitize_hex_color($attrs['color']) : '#23D366';
921 $border_type = isset($attrs['border_type']) ? sanitize_text_field($attrs['border_type']) : null;
922 $margin = [
923 "top" => isset($attrs['margin_top']) ? intval($attrs['margin_top']) : 4,
924 "bottom" => isset($attrs['margin_bottom']) ? intval($attrs['margin_bottom']) : 4,
925 "left" => isset($attrs['margin_left']) ? intval($attrs['margin_left']) : 0,
926 "right" => isset($attrs['margin_right']) ? intval($attrs['margin_right']) : 0,
927 ];
928 $padding = [
929 "top" => isset($attrs['padding_top']) ? intval($attrs['padding_top']) : 8,
930 "bottom" => isset($attrs['padding_bottom']) ? intval($attrs['padding_bottom']) : 8,
931 "left" => isset($attrs['padding_left']) ? intval($attrs['padding_left']) : 14,
932 "right" => isset($attrs['padding_right']) ? intval($attrs['padding_right']) : 14,
933 ];
934 $font_size = isset($attrs['font_size']) ? intval($attrs['font_size']) : 12;
935 $id = isset($attrs['id']) ? sanitize_html_class($attrs['id']) : '';
936 $class_names = isset($attrs['class_names']) ? sanitize_html_class($attrs['class_names']) : '';
937 $custom_css = isset($attrs['custom_css']) ? wp_kses_post($attrs['custom_css']) : '';
938
939 Spoki()->render_relative_button($phone, $cta, $title, $final_message, $additional_class, $type, $margin, $padding, $color, $border_type, $font_size, '', $id, $class_names, $custom_css);
940 }
941
942
943 add_shortcode('spoki_button', 'spoki_button_shortcode');
944
945 add_action('wp_footer', array($this, 'render_shadowed_buttons'));
946 }
947
948 public function disable_checkout_button()
949 {
950 remove_action('woocommerce_proceed_to_checkout', 'woocommerce_button_proceed_to_checkout', 20);
951 }
952
953 /**
954 *
955 */
956 public function render_shadowed_buttons()
957 {
958 echo "<script>";
959 include_once SPOKI_DIR . 'assets/js/spoki-shadowed-buttons.js';
960 echo "</script>";
961 }
962
963 /**
964 * Render the WhatsApp FAB on the website in every page
965 */
966 public function render_floating_button()
967 {
968 if (isset($this->options['telephone']) && $this->options['telephone'] != '') {
969
970 /** Check visibility conditions */
971 $hide_on_posts = isset($this->options['buttons']['fixed_support_button_hide_post_page']) && $this->options['buttons']['fixed_support_button_hide_post_page'] == 1;
972 if ($hide_on_posts && is_single() && 'post' == get_post_type()) {
973 return;
974 }
975 $hide_on_pages = isset($this->options['buttons']['fixed_support_button_hide_single_page']) && $this->options['buttons']['fixed_support_button_hide_single_page'] == 1;
976 if ($hide_on_pages && is_page() && 'page' == get_post_type()) {
977 return;
978 }
979 $hide_on_shop = isset($this->options['buttons']['fixed_support_button_hide_shop_page']) && $this->options['buttons']['fixed_support_button_hide_shop_page'] == 1;
980 if ($hide_on_shop && is_shop()) {
981 return;
982 }
983 $hide_on_product = isset($this->options['buttons']['fixed_support_button_hide_product_page']) && $this->options['buttons']['fixed_support_button_hide_product_page'] == 1;
984 if ($hide_on_product && is_product()) {
985 return;
986 }
987 $hide_on_cart = isset($this->options['buttons']['fixed_support_button_hide_cart_page']) && $this->options['buttons']['fixed_support_button_hide_cart_page'] == 1;
988 if ($hide_on_cart && is_cart()) {
989 return;
990 }
991 $hide_on_checkout = isset($this->options['buttons']['fixed_support_button_hide_checkout_page']) && $this->options['buttons']['fixed_support_button_hide_checkout_page'] == 1;
992 if ($hide_on_checkout && (is_checkout() || is_checkout_pay_page())) {
993 return;
994 }
995 $hide_non_working = isset($this->options['buttons']['fixed_support_button_hide_non_working']) && $this->options['buttons']['fixed_support_button_hide_non_working'] == 1;
996 $is_working_days_times_enabled = isset($this->options['working_days_times']['enabled']) && $this->options['working_days_times']['enabled'] == 1;
997 $is_non_working_day_time = isset($this->options['working_days_times']) && spoki_is_non_working_day_time($this->options['working_days_times']);;
998 if ($hide_non_working && $is_working_days_times_enabled && $is_non_working_day_time) {
999 return;
1000 }
1001
1002 /** Can render, go on */
1003 $prefix = isset($this->options['prefix']) ? $this->options['prefix'] : '';
1004 $phone = $prefix . $this->options['telephone'];
1005 $text = $this->options['buttons']['fixed_support_button_text'];
1006 $is_non_working_days_times_text_enabled = isset($this->options['buttons']['fixed_support_button_non_working_text_enabled']) && $this->options['buttons']['fixed_support_button_non_working_text_enabled'] == 1;
1007 if ($is_non_working_day_time && $is_non_working_days_times_text_enabled) {
1008 $text = isset($this->options['buttons']['fixed_support_button_non_working_text']) ? $this->options['buttons']['fixed_support_button_non_working_text'] : "";
1009 }
1010 $position = $this->options['buttons']['fixed_support_button_position'] == 'Left' ? 'left' : 'right';
1011 $border_type = isset($this->options['buttons']['fixed_support_button_border']) ? $this->options['buttons']['fixed_support_button_border'] : 'circle';
1012 $size = isset($this->options['buttons']['fixed_support_button_size']) ? $this->options['buttons']['fixed_support_button_size'] : '50';
1013 $icon_size = '65%';
1014 $border_radius = '50%';
1015 if ($border_type == 'squared') {
1016 $border_radius = '0';
1017 } elseif ($border_type == 'rounded') {
1018 $border_radius = '8px';
1019 }
1020 $color = isset($this->options['buttons']['fixed_support_button_color']) ? $this->options['buttons']['fixed_support_button_color'] : '#23D366';
1021 $bottom_space = isset($this->options['buttons']['fixed_support_button_bottom_space']) ? $this->options['buttons']['fixed_support_button_bottom_space'] : '12';
1022 $side_space = isset($this->options['buttons']['fixed_support_button_side_space']) ? $this->options['buttons']['fixed_support_button_side_space'] : '12';
1023 $furl = get_bloginfo('url');
1024 $wa_link = SPOKI_BASE_API_BUTTONS . "?type=1&phone=$phone&text=" . urlencode($text) . "&furl=$furl";
1025
1026 $spoki_fixed_btn_label = "";
1027 $has_label = isset($this->options['buttons']['fixed_support_button_show_label']) && $this->options['buttons']['fixed_support_button_show_label'] == 1;
1028 if ($has_label) {
1029 $show_on_hover = (isset($this->options['buttons']['fixed_support_button_show_label_on_hover']) && $this->options['buttons']['fixed_support_button_show_label_on_hover'] == 1) ? 'hide-not-hover' : '';
1030 $label_space = intval($size) + 12;
1031 $label_content = (isset($this->options['buttons']['fixed_support_button_label_content']) && $this->options['buttons']['fixed_support_button_label_content'] != "") ? $this->options['buttons']['fixed_support_button_label_content'] : __('Chat with us 👋', "spoki");
1032 $label_font_size = (isset($this->options['buttons']['fixed_support_button_label_font_size']) && $this->options['buttons']['fixed_support_button_label_font_size'] != "") ? $this->options['buttons']['fixed_support_button_label_font_size'] : '16';
1033 $label_text_color = isset($this->options['buttons']['fixed_support_button_label_text_color']) ? $this->options['buttons']['fixed_support_button_label_text_color'] : '#333333';
1034 $label_background_color = isset($this->options['buttons']['fixed_support_button_label_background_color']) ? $this->options['buttons']['fixed_support_button_label_background_color'] : '#FFFFFF';
1035 $label_border_radius = $border_type == 'squared' ? '0' : '10';
1036 $label_delay = (intval((isset($this->options['buttons']['fixed_support_button_label_delay']) && $this->options['buttons']['fixed_support_button_label_delay'] != "") ? $this->options['buttons']['fixed_support_button_label_delay'] : '0') * 1000) + 1000;
1037 $spoki_fixed_btn_label = "<div class='spoki-fixed-btn-label $show_on_hover' style='display:none;$position:{$label_space}px;font-size:{$label_font_size}px;color:$label_text_color;background-color:$label_background_color;border-radius:{$label_border_radius}px;'>$label_content</div><script>(function (d) {setTimeout(function (){try {const shadowedButton = d.querySelector('#spoki-shadowed-fixed-button'); if (shadowedButton) {shadowedButton.shadowRoot.querySelector('.spoki-fixed-btn-label').style.display ='';}} catch (e) {console.log(e)}}, $label_delay)})(document)</script>";
1038 }
1039
1040 $spoki_fixed_btn_popup = "";
1041 $has_popup = isset($this->options['buttons']['fixed_support_button_show_popup']) && $this->options['buttons']['fixed_support_button_show_popup'] == 1;
1042 if ($has_popup) {
1043 $spoki_fixed_btn_popup_delay = (intval((isset($this->options['buttons']['fixed_support_button_popup_delay']) && $this->options['buttons']['fixed_support_button_popup_delay'] != "") ? $this->options['buttons']['fixed_support_button_popup_delay'] : '0') * 1000) + 1000;
1044 $spoki_fixed_btn_popup = "<span class='spoki-fixed-btn-popup' style='display: none;'>1</span><script>(function (d) {setTimeout(function (){try {const shadowedButton = d.querySelector('#spoki-shadowed-fixed-button'); if (shadowedButton) {shadowedButton.shadowRoot.querySelector('.spoki-fixed-btn-popup').style.display ='';}} catch (e) {console.log(e)}}, $spoki_fixed_btn_popup_delay)})(document)</script>";
1045 }
1046
1047 $hidden_mobile = isset($this->options['buttons']['fixed_support_button_hide_mobile']) && $this->options['buttons']['fixed_support_button_hide_mobile'] == 1 ? "hidden-mobile" : "";
1048 $hidden_tablet = isset($this->options['buttons']['fixed_support_button_hide_tablet']) && $this->options['buttons']['fixed_support_button_hide_tablet'] == 1 ? "hidden-tablet" : "";
1049 $hidden_desktop = isset($this->options['buttons']['fixed_support_button_hide_desktop']) && $this->options['buttons']['fixed_support_button_hide_desktop'] == 1 ? "hidden-desktop" : "";
1050 $class = "$hidden_mobile $hidden_tablet $hidden_desktop";
1051
1052 $chat_widget = "";
1053 $has_chat_widget = isset($this->options['buttons']['fixed_support_button_show_chat_widget']) && $this->options['buttons']['fixed_support_button_show_chat_widget'] == 1;
1054 if ($has_chat_widget) {
1055 $background_image_url = plugins_url() . '/' . SPOKI_PLUGIN_NAME . '/assets/images/wa-background.jpeg';
1056 $from_message = $this->options['buttons']['fixed_support_button_chat_widget_message'];
1057 $send_icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="currentColor" d="M1.101 21.757L23.8 12.028 1.101 2.3l.011 7.912 13.623 1.816-13.623 1.817-.011 7.912z"></path></svg>';
1058 $chat_widget_delay = intval((isset($this->options['buttons']['fixed_support_button_chat_widget_delay']) && $this->options['buttons']['fixed_support_button_chat_widget_delay'] != "") ? $this->options['buttons']['fixed_support_button_chat_widget_delay'] : '0') * 1000;
1059 $chat_widget_delay_script = "";
1060 if ($chat_widget_delay != 0) {
1061 $chat_widget_delay = $chat_widget_delay + 1000;
1062 $chat_widget_delay_script = "<script>(function (d) {setTimeout(function (){try {const shadowedButton = d.querySelector('#spoki-shadowed-fixed-button'); if (shadowedButton) {shadowedButton.shadowRoot.querySelector('#spoki-chat-preview').classList.remove('hidden')}} catch (e) {console.log(e)}}, $chat_widget_delay)})(document)</script>";
1063 }
1064 $chat_widget_script = "<script>(function (d) {setTimeout(function(){const shadowedButton = d.querySelector('#spoki-shadowed-fixed-button'); if (shadowedButton) {shadowedButton.shadowRoot.querySelector('#spoki-chat-link').addEventListener('click', function(e){e.preventDefault();document.querySelector('#spoki-shadowed-fixed-button').shadowRoot.querySelector('#spoki-chat-preview').classList.toggle('hidden')})}}, 1000)})(document)</script>$chat_widget_delay_script";
1065 $link = SPOKI_BASE_API_BUTTONS;
1066 $furl = get_bloginfo('url');
1067 $chat_widget = "<div id='spoki-chat-preview' class='hidden' style='bottom:{$size}px;background-image: url(\"{$background_image_url}\")'><div class='spoki-chat-preview-chat-message'>{$from_message}</div><div id='spoki-chat-preview-footer'><form method='get' target='_blank' action='$link'><input type='hidden' name='phone' value='{$phone}'/><input type='hidden' name='furl' value='{$furl}'/><input type='hidden' name='type' value='1'/><input id='spoki-chat-preview-message' type='text' name='text' value='$text' /><button id='spoki-chat-preview-send' type='submit'>{$send_icon}</button></form></div></div>$chat_widget_script";
1068 }
1069
1070 echo "<div id='spoki-shadowed-fixed-button' class='spoki-shadowed-button'><div id='spoki-fixed-btn' class='$class' style='$position:{$side_space}px;bottom:{$bottom_space}px;'>{$chat_widget}{$spoki_fixed_btn_label}{$spoki_fixed_btn_popup}<a id='spoki-chat-link' style='background-color:{$color};border-radius:$border_radius;height:{$size}px;width:{$size}px;' href='$wa_link' target='_blank' rel='nofollow'>" . spoki_get_wa_logo($size) . "</a></div></div>";
1071 }
1072 }
1073
1074 /**
1075 * Render the product button for every product in shop page
1076 */
1077 public function render_product_item_listing_button()
1078 {
1079 global $product;
1080 $hide_non_working = isset($this->options['woocommerce']['product_item_listing_button_hide_non_working']) && $this->options['woocommerce']['product_item_listing_button_hide_non_working'] == 1;
1081 $is_working_days_times_enabled = isset($this->options['working_days_times']['enabled']) && $this->options['working_days_times']['enabled'] == 1;
1082 $is_non_working_day_time = isset($this->options['working_days_times']) && spoki_is_non_working_day_time($this->options['working_days_times']);;
1083 if ($hide_non_working && $is_working_days_times_enabled && $is_non_working_day_time) {
1084 return;
1085 }
1086
1087 $prefix = isset($this->options['prefix']) ? $this->options['prefix'] : '';
1088 $phone = $prefix . $this->options['telephone'];
1089 $cta = __("Request support on WhatsApp", "spoki");
1090 if (isset($this->options['woocommerce']['product_item_listing_button_cta']) && !empty($this->options['woocommerce']['product_item_listing_button_cta'])) {
1091 $cta = $this->options['woocommerce']['product_item_listing_button_cta'];
1092 }
1093 $message = __("Hi, I want to buy:", "spoki");
1094 if (isset($this->options['woocommerce']['product_item_listing_button_text']) && !empty($this->options['woocommerce']['product_item_listing_button_text'])) {
1095 $message = $this->options['woocommerce']['product_item_listing_button_text'];
1096 }
1097 $is_non_working_days_times_text_enabled = isset($this->options['woocommerce']['product_item_listing_button_non_working_text_enabled']) && $this->options['woocommerce']['product_item_listing_button_non_working_text_enabled'] == 1;
1098 if ($is_non_working_day_time && $is_non_working_days_times_text_enabled) {
1099 $message = isset($this->options['woocommerce']['product_item_listing_button_non_working_text']) ? $this->options['woocommerce']['product_item_listing_button_non_working_text'] : "";
1100 }
1101 $color = isset($this->options['woocommerce']['product_item_listing_button_color']) ? $this->options['woocommerce']['product_item_listing_button_color'] : '#23D366';
1102 $font_size = isset($this->options['woocommerce']['product_item_listing_button_font_size']) ? $this->options['woocommerce']['product_item_listing_button_font_size'] : '12';
1103 $border_type = isset($this->options['woocommerce']['product_item_listing_button_border']) ? $this->options['woocommerce']['product_item_listing_button_border'] : 'rounded';
1104
1105 $margin = [
1106 "top" => isset($this->options['woocommerce']['product_item_listing_button_margin_top']) ? $this->options['woocommerce']['product_item_listing_button_margin_top'] : '4',
1107 "bottom" => isset($this->options['woocommerce']['product_item_listing_button_margin_bottom']) ? $this->options['woocommerce']['product_item_listing_button_margin_bottom'] : '4',
1108 "left" => isset($this->options['woocommerce']['product_item_listing_button_margin_left']) ? $this->options['woocommerce']['product_item_listing_button_margin_left'] : '0',
1109 "right" => isset($this->options['woocommerce']['product_item_listing_button_margin_right']) ? $this->options['woocommerce']['product_item_listing_button_margin_right'] : '0',
1110 ];
1111
1112 $padding = [
1113 "top" => isset($this->options['woocommerce']['product_item_listing_button_padding_top']) ? $this->options['woocommerce']['product_item_listing_button_padding_top'] : '8',
1114 "bottom" => isset($this->options['woocommerce']['product_item_listing_button_padding_bottom']) ? $this->options['woocommerce']['product_item_listing_button_padding_bottom'] : '8',
1115 "left" => isset($this->options['woocommerce']['product_item_listing_button_padding_left']) ? $this->options['woocommerce']['product_item_listing_button_padding_left'] : '14',
1116 "right" => isset($this->options['woocommerce']['product_item_listing_button_padding_right']) ? $this->options['woocommerce']['product_item_listing_button_padding_right'] : '14',
1117 ];
1118
1119 $this->render_product_button($product, $phone, $cta, $message, $margin, $padding, $color, $border_type, $font_size, true);
1120 }
1121
1122 /**
1123 * Render the button in the cart page
1124 */
1125 public function render_cart_button()
1126 {
1127 global $product;
1128 $hide_non_working = isset($this->options['woocommerce']['cart_button_hide_non_working']) && $this->options['woocommerce']['cart_button_hide_non_working'] == 1;
1129 $is_working_days_times_enabled = isset($this->options['working_days_times']['enabled']) && $this->options['working_days_times']['enabled'] == 1;
1130 $is_non_working_day_time = isset($this->options['working_days_times']) && spoki_is_non_working_day_time($this->options['working_days_times']);;
1131 if ($hide_non_working && $is_working_days_times_enabled && $is_non_working_day_time) {
1132 return;
1133 }
1134 $prefix = isset($this->options['prefix']) ? $this->options['prefix'] : '';
1135 $phone = $prefix . $this->options['telephone'];
1136 $cta = __("Order via WhatsApp", "spoki");
1137 if (isset($this->options['woocommerce']['cart_button_cta']) && !empty($this->options['woocommerce']['cart_button_cta'])) {
1138 $cta = $this->options['woocommerce']['cart_button_cta'];
1139 }
1140 $message = __("Hi, I want to buy:", "spoki");
1141 if (isset($this->options['woocommerce']['cart_button_text']) && !empty($this->options['woocommerce']['cart_button_text'])) {
1142 $message = $this->options['woocommerce']['cart_button_text'];
1143 }
1144 $is_non_working_days_times_text_enabled = isset($this->options['woocommerce']['cart_button_non_working_text_enabled']) && $this->options['woocommerce']['cart_button_non_working_text_enabled'] == 1;
1145 if ($is_non_working_day_time && $is_non_working_days_times_text_enabled) {
1146 $message = isset($this->options['woocommerce']['cart_button_non_working_text']) ? $this->options['woocommerce']['cart_button_non_working_text'] : "";
1147 }
1148 $color = isset($this->options['woocommerce']['cart_button_color']) ? $this->options['woocommerce']['cart_button_color'] : '#23D366';
1149 $font_size = isset($this->options['woocommerce']['cart_button_font_size']) ? $this->options['woocommerce']['cart_button_font_size'] : '12';
1150 $icon_size = intval($font_size) < 16 ? 16 : $font_size;
1151 $final_message = urlencode($message);
1152 $products = WC()->cart->get_cart();
1153
1154 foreach ($products as $item) {
1155 $product_id = $item['product_id'];
1156 $qty = $item['quantity'];
1157 $product = wc_get_product($product_id);
1158 $product_url = $product->get_permalink();
1159 $product_title = $product->get_name();
1160 $price = wp_strip_all_tags(wc_price(wc_get_price_including_tax($product)));
1161 $encoded_title = urlencode($product_title);
1162 $encoded_product_url = urlencode($product_url);
1163 $final_message .= "%0D%0A%0D%0A_(ID:%20$product_id)_%20*$encoded_title*%20$price%20x$qty%0D%0A$encoded_product_url";
1164 }
1165 $shipping_total_value = WC()->cart->get_shipping_total() + WC()->cart->get_shipping_tax();
1166 if ($shipping_total_value > 0) {
1167 $shipping_label = '';
1168 $chosen_methods = WC()->session ? WC()->session->get('chosen_shipping_methods') : null;
1169 if (is_array($chosen_methods) && !empty($chosen_methods)) {
1170 $chosen_method_id = reset($chosen_methods);
1171 foreach (WC()->shipping()->get_packages() as $package) {
1172 if (isset($package['rates'][$chosen_method_id])) {
1173 $shipping_label = $package['rates'][$chosen_method_id]->get_label();
1174 break;
1175 }
1176 }
1177 }
1178 $shipping_price = wp_strip_all_tags(wc_price($shipping_total_value));
1179 $shipping_text = __("Shipping", "spoki");
1180 if (!empty($shipping_label)) {
1181 $shipping_text .= ' (' . $shipping_label . ')';
1182 }
1183 $encoded_shipping_text = urlencode($shipping_text);
1184 $final_message .= "%0D%0A%0D%0A*$encoded_shipping_text*:%20$shipping_price";
1185 }
1186 $total = wp_strip_all_tags(wc_price(WC()->cart->get_total('edit')));
1187 $final_message .= "%0D%0A%0D%0A*" . __("Total", "spoki") . "*: %20$total%20";
1188
1189 $furl = get_bloginfo('url');
1190 $href = SPOKI_BASE_API_BUTTONS . "?type=4&phone=$phone&text=$final_message&furl=$furl";
1191 $title = "$cta";
1192 $class = 'button spoki-button size-4';
1193 $border_type = isset($this->options['woocommerce']['cart_button_border']) ? $this->options['woocommerce']['cart_button_border'] : 'rounded';
1194
1195 $border_radius = '16px';
1196 if ($border_type == 'squared') {
1197 $border_radius = '0';
1198 }
1199
1200 $margin = [
1201 "top" => isset($this->options['woocommerce']['cart_button_margin_top']) ? $this->options['woocommerce']['cart_button_margin_top'] : '4',
1202 "bottom" => isset($this->options['woocommerce']['cart_button_margin_bottom']) ? $this->options['woocommerce']['cart_button_margin_bottom'] : '4',
1203 "left" => isset($this->options['woocommerce']['cart_button_margin_left']) ? $this->options['woocommerce']['cart_button_margin_left'] : '0',
1204 "right" => isset($this->options['woocommerce']['cart_button_margin_right']) ? $this->options['woocommerce']['cart_button_margin_right'] : '0',
1205 ];
1206 $padding = [
1207 "top" => isset($this->options['woocommerce']['cart_button_padding_top']) ? $this->options['woocommerce']['cart_button_padding_top'] : '8',
1208 "bottom" => isset($this->options['woocommerce']['cart_button_padding_bottom']) ? $this->options['woocommerce']['cart_button_padding_bottom'] : '8',
1209 "left" => isset($this->options['woocommerce']['cart_button_padding_left']) ? $this->options['woocommerce']['cart_button_padding_left'] : '14',
1210 "right" => isset($this->options['woocommerce']['cart_button_padding_right']) ? $this->options['woocommerce']['cart_button_padding_right'] : '14',
1211 ];
1212
1213 $margin_style = "margin-top:{$margin['top']}px;margin-bottom:{$margin['bottom']}px;margin-left:{$margin['left']}px;margin-right:{$margin['right']}px;";
1214 $padding_style = "padding-top:{$padding['top']}px;padding-bottom:{$padding['bottom']}px;padding-left:{$padding['left']}px;padding-right:{$padding['right']}px;";
1215
1216 echo "<div class='spoki-shadowed-button'><div class='spoki-button-relative' style='{$margin_style}'><a href='$href' target='_blank' rel='nofollow' title='$title' class='$class' style='background-color:$color;border-radius:$border_radius;font-size:{$font_size}px;{$padding_style}'>" . spoki_get_wa_logo($icon_size) . "<span>$cta</span></a></div></div>";
1217 }
1218
1219 /**
1220 * Render the button in the product page
1221 */
1222 public function render_single_product_button()
1223 {
1224 global $product;
1225 $hide_non_working = isset($this->options['woocommerce']['single_product_button_hide_non_working']) && $this->options['woocommerce']['single_product_button_hide_non_working'] == 1;
1226 $is_working_days_times_enabled = isset($this->options['working_days_times']['enabled']) && $this->options['working_days_times']['enabled'] == 1;
1227 $is_non_working_day_time = isset($this->options['working_days_times']) && spoki_is_non_working_day_time($this->options['working_days_times']);
1228 if ($hide_non_working && $is_working_days_times_enabled && $is_non_working_day_time) {
1229 return;
1230 }
1231
1232 $prefix = isset($this->options['prefix']) ? $this->options['prefix'] : '';
1233 $phone = $prefix . $this->options['telephone'];
1234 $cta = __("Request support on WhatsApp", "spoki");
1235 if (isset($this->options['woocommerce']['single_product_button_cta']) && !empty($this->options['woocommerce']['single_product_button_cta'])) {
1236 $cta = $this->options['woocommerce']['single_product_button_cta'];
1237 }
1238 $message = __("Hi, I want to buy:", "spoki");
1239 if (isset($this->options['woocommerce']['single_product_button_text']) && !empty($this->options['woocommerce']['single_product_button_text'])) {
1240 $message = $this->options['woocommerce']['single_product_button_text'];
1241 }
1242 $is_non_working_days_times_text_enabled = isset($this->options['woocommerce']['single_product_button_non_working_text_enabled']) && $this->options['woocommerce']['single_product_button_non_working_text_enabled'] == 1;
1243 if ($is_non_working_day_time && $is_non_working_days_times_text_enabled) {
1244 $message = isset($this->options['woocommerce']['single_product_button_non_working_text']) ? $this->options['woocommerce']['single_product_button_non_working_text'] : "";
1245 }
1246 $position = isset($this->options['woocommerce']['single_product_button_position']) ? $this->options['woocommerce']['single_product_button_position'] : 'after_atc';
1247 $color = isset($this->options['woocommerce']['single_product_button_color']) ? $this->options['woocommerce']['single_product_button_color'] : '#23D366';
1248 $font_size = isset($this->options['woocommerce']['single_product_button_font_size']) ? $this->options['woocommerce']['single_product_button_font_size'] : '12';
1249 $border_type = isset($this->options['woocommerce']['single_product_button_border']) ? $this->options['woocommerce']['single_product_button_border'] : 'rounded';
1250
1251 $margin = [
1252 "top" => isset($this->options['woocommerce']['single_product_button_margin_top']) ? $this->options['woocommerce']['single_product_button_margin_top'] : '4',
1253 "bottom" => isset($this->options['woocommerce']['single_product_button_margin_bottom']) ? $this->options['woocommerce']['single_product_button_margin_bottom'] : '4',
1254 "left" => isset($this->options['woocommerce']['single_product_button_margin_left']) ? $this->options['woocommerce']['single_product_button_margin_left'] : '0',
1255 "right" => isset($this->options['woocommerce']['single_product_button_margin_right']) ? $this->options['woocommerce']['single_product_button_margin_right'] : '0',
1256 ];
1257
1258 $padding = [
1259 "top" => isset($this->options['woocommerce']['single_product_button_padding_top']) ? $this->options['woocommerce']['single_product_button_padding_top'] : '8',
1260 "bottom" => isset($this->options['woocommerce']['single_product_button_padding_bottom']) ? $this->options['woocommerce']['single_product_button_padding_bottom'] : '8',
1261 "left" => isset($this->options['woocommerce']['single_product_button_padding_left']) ? $this->options['woocommerce']['single_product_button_padding_left'] : '14',
1262 "right" => isset($this->options['woocommerce']['single_product_button_padding_right']) ? $this->options['woocommerce']['single_product_button_padding_right'] : '14',
1263 ];
1264
1265 $this->render_product_button($product, $phone, $cta, $message, $margin, $padding, $color, $border_type, $font_size, false, $position);
1266 }
1267
1268 /**
1269 * Render the button of a product
1270 *
1271 * @param $product
1272 * @param $phone
1273 * @param $cta
1274 * @param $message
1275 * @param null $position
1276 */
1277 public function render_product_button($product, $phone, $cta, $message, $margin, $padding, $color = '#23D366', $border_type = 'rounded', $font_size = '12', $is_listing = false, $position = null)
1278 {
1279 $product_url = $product->get_permalink();
1280 $product_title = $product->get_name();
1281 $product_id = $product->get_id();
1282 $price = wp_strip_all_tags(wc_price(wc_get_price_including_tax($product)));
1283 $encoded_message = urlencode($message);
1284 $encoded_title = urlencode($product_title);
1285 $encoded_product_url = urlencode($product_url);
1286 $final_message = "$encoded_message%20%20%0D%0A(ID:%20$product_id)%20*$encoded_title*%20$price%20%20%0D%0A$encoded_product_url";
1287 $type = $is_listing ? '2' : '3';
1288 $title = "$cta $product_title";
1289 $additional_class = sprintf('product_type_%s', $product->get_type());
1290
1291 $this->render_relative_button($phone, $cta, $title, $final_message, $additional_class, $type, $margin, $padding, $color, $border_type, $font_size, $position);
1292 }
1293
1294 /**
1295 * Render a relative button
1296 */
1297 public function render_relative_button($phone, $cta, $title, $final_message, $additional_class, $type, $margin, $padding, $color = '#23D366', $border_type = 'rounded', $font_size = '12', $position = null, $id = '', $class_names = '', $custom_css = '')
1298 {
1299 $class = sprintf('button spoki-button %s', esc_attr(sanitize_html_class($additional_class)));
1300 if (isset($position)) {
1301 $class .= " size-2 $position";
1302 } else {
1303 $class .= " size-4";
1304 }
1305
1306 $border_radius = '16px';
1307 if ($border_type == 'squared') {
1308 $border_radius = '0';
1309 }
1310
1311 $furl = get_bloginfo('url');
1312 $href = SPOKI_BASE_API_BUTTONS . "?type={$type}&phone=" . rawurlencode($phone) . "&text=" . $final_message . "&furl=" . rawurlencode($furl);
1313 $icon_size = intval($font_size) < 16 ? 16 : $font_size;
1314
1315 $margin_style = "margin-top:" . esc_attr($margin['top']) . "px;margin-bottom:" . esc_attr($margin['bottom']) . "px;margin-left:" . esc_attr($margin['left']) . "px;margin-right:" . esc_attr($margin['right']) . "px;";
1316 $padding_style = "padding-top:" . esc_attr($padding['top']) . "px;padding-bottom:" . esc_attr($padding['bottom']) . "px;padding-left:" . esc_attr($padding['left']) . "px;padding-right:" . esc_attr($padding['right']) . "px;";
1317
1318 echo "<div class='spoki-shadowed-button'><div class='spoki-button-relative " . esc_attr(sanitize_html_class($class_names)) . "' id='" . esc_attr(sanitize_html_class($id)) . "' style='{$margin_style}'><a href='". esc_url($href) ."' target='_blank' rel='nofollow' title='" . esc_attr($title) . "' class='{$class}' style='background-color:" . esc_attr(sanitize_hex_color($color)) . ";border-radius:" . esc_attr($border_radius) . ";font-size:" . esc_attr($font_size) . "px;{$padding_style}'>" . spoki_get_wa_logo($icon_size) . "<span>" . esc_html($cta) . "</span></a><style>" . wp_kses_post($custom_css) . "</style></div></div>";
1319 }
1320
1321 /**
1322 * Get the link to change plan to pro
1323 *
1324 * @return string
1325 */
1326 public function get_pro_plan_link(): string
1327 {
1328 return 'https://spoki.com/en/pricing/';
1329 }
1330
1331 /**
1332 * Update Spoki options
1333 *
1334 * @param $current_options
1335 * @param $new_options
1336 */
1337 private function update_options($current_options, $new_options)
1338 {
1339 $c_options = is_array($current_options) ? $current_options : [];
1340 if (isset($new_options["woocommerce"])) {
1341 $woocommerce = [];
1342 if (isset($c_options["abandoned_carts"])) {
1343 $woocommerce = array_merge($c_options["woocommerce"], $new_options["woocommerce"]);
1344 } else {
1345 $woocommerce = $new_options["woocommerce"];
1346 }
1347 $new_options["woocommerce"] = $woocommerce;
1348 }
1349 if (isset($new_options["abandoned_carts"])) {
1350 $abandoned_carts = [];
1351 if (isset($c_options["abandoned_carts"])) {
1352 $abandoned_carts = array_merge($c_options["abandoned_carts"], $new_options["abandoned_carts"]);
1353 } else {
1354 $abandoned_carts = $new_options["abandoned_carts"];
1355 }
1356 $new_options["abandoned_carts"] = $abandoned_carts;
1357 }
1358 if (isset($new_options["secret_status"])) {
1359 $secret_status = [];
1360 if (isset($c_options["secret_status"])) {
1361 $secret_status = array_merge($c_options["secret_status"], $new_options["secret_status"]);
1362 } else {
1363 $secret_status = $new_options["secret_status"];
1364 }
1365 $new_options["secret_status"] = $secret_status;
1366 }
1367 if (isset($new_options["account_info"])) {
1368 $account_info = [];
1369 if (isset($c_options["account_info"])) {
1370 $account_info = array_merge($c_options["account_info"], $new_options["account_info"]);
1371 } else {
1372 $account_info = $new_options["account_info"];
1373 }
1374 $new_options["account_info"] = $account_info;
1375 }
1376 update_option(SPOKI_OPTIONS, array_merge($c_options, $new_options));
1377 $this->options = get_option(SPOKI_OPTIONS);
1378 }
1379
1380 /**
1381 * Check the secret status periodically
1382 */
1383 public function check_secret_status()
1384 {
1385 $this->fetch_secret_status(true);
1386 }
1387
1388 /**
1389 * Fetch the status of the Spoki keys
1390 */
1391 public function fetch_secret_status($force_checking = false)
1392 {
1393 $response = null;
1394 if ($force_checking) {
1395 $response = $this->check_spoki_status();
1396 }
1397
1398 if (!isset($this->options['secret']) || $this->options['secret'] == '' || !isset($this->options['delivery_url']) || $this->options['delivery_url'] == '') {
1399 $this->update_options(get_option(SPOKI_OPTIONS), ["secret_status" => [
1400 'secret' => isset($this->options['secret']) ? $this->options['secret'] : '',
1401 'delivery_url' => isset($this->options['delivery_url']) ? $this->options['delivery_url'] : '',
1402 'code' => 0,
1403 'message' => ''
1404 ]]);
1405 } else if (!isset($this->options['secret_status']) || $this->options['secret_status']['code'] != 200 || $this->options['secret'] != $this->options['secret_status']['secret'] || $this->options['delivery_url'] != $this->options['secret_status']['delivery_url']) {
1406 if (!$force_checking) {
1407 $response = $this->check_spoki_status();
1408 }
1409 $this->update_options(get_option(SPOKI_OPTIONS), ["secret_status" => [
1410 'secret' => isset($this->options['secret']) ? $this->options['secret'] : '',
1411 'delivery_url' => isset($this->options['delivery_url']) ? $this->options['delivery_url'] : '',
1412 'code' => wp_remote_retrieve_response_code($response),
1413 'message' => wp_remote_retrieve_response_message($response)
1414 ]]);
1415 }
1416 return $response;
1417 }
1418
1419 /**
1420 * Activation Reset
1421 */
1422 public function activation_reset()
1423 {
1424 register_uninstall_hook(SPOKI_PLUGIN_FILE, array($this, 'uninstall_plugin'));
1425 if (!class_exists('WooCommerce')) {
1426 return;
1427 }
1428 $this->initialize_cart_abandonment_tables();
1429 $Abandonment = Spoki_Abandoned_Carts::instance();
1430 $spokiDomain = $Abandonment->get_spoki_setting_by_meta("spoki_domain");
1431 $Abandonment->set_spoki_setting_by_meta("plugin_activated", "true");
1432 if ($spokiDomain != null || $spokiDomain != "")
1433 $Abandonment->save_webhook_url($spokiDomain);
1434 }
1435
1436 /**
1437 * Deactivation Reset
1438 */
1439 public function deactivation_reset()
1440 {
1441 $Abandonment = Spoki_Abandoned_Carts::instance();
1442 # Unschedule hook for versions <= v2.8.1
1443 $Abandonment->unschedule_hook();
1444 if (!class_exists('WooCommerce')) {
1445 return;
1446 }
1447 $spokiDomain = $Abandonment->get_spoki_setting_by_meta("spoki_domain");
1448 $Abandonment->set_spoki_setting_by_meta("plugin_activated", "false");
1449 if ($spokiDomain != null || $spokiDomain != "")
1450 $Abandonment->disable_webhook_url($spokiDomain);
1451 }
1452
1453 /**
1454 * Uninstall Plugin
1455 */
1456 public function uninstall_plugin()
1457 {
1458 if (!class_exists('WooCommerce')) {
1459 return;
1460 }
1461 $Abandonment = Spoki_Abandoned_Carts::instance();
1462 $spokiDomain = $Abandonment->get_spoki_setting_by_meta("spoki_domain");
1463 $Abandonment->set_spoki_setting_by_meta("plugin_activated", "false");
1464 if ($spokiDomain != null || $spokiDomain != "")
1465 $Abandonment->disable_webhook_url($spokiDomain);
1466 }
1467 }
1468
1469 /**
1470 * Executed on activation of the plugin.
1471 * Redirects the user after plugin activation.
1472 */
1473 function spoki_activation()
1474 {
1475 if (!((isset($_REQUEST['action']) && 'activate-selected' === $_REQUEST['action']) && (isset($_POST['checked']) && count($_POST['checked']) > 1))) {
1476 add_option('spoki_activation_redirect', true);
1477 }
1478 }
1479
1480 /**
1481 * Redirects the user after plugin activation.
1482 */
1483 function spoki_activation_redirect()
1484 {
1485 if (get_option('spoki_activation_redirect', false)) {
1486 delete_option('spoki_activation_redirect');
1487 exit(wp_redirect(admin_url('/admin.php?page=' . SPOKI_PLUGIN_NAME)));
1488 }
1489 }
1490
1491 /**
1492 * Executed on deactivation of the plugin
1493 */
1494 function spoki_deactivation()
1495 {
1496 // delete_option(SPOKI_OPTIONS);
1497 $timestamp = wp_next_scheduled('spoki_cron_hook');
1498 wp_unschedule_event($timestamp, 'spoki_cron_hook');
1499 }
1500
1501 register_deactivation_hook(__FILE__, 'spoki_deactivation');
1502 register_activation_hook(__FILE__, 'spoki_activation');
1503 add_action('admin_init', 'spoki_activation_redirect');
1504