PluginProbe
Spoki – Chat Buttons and WooCommerce Notifications / 2.0.9
Spoki – Chat Buttons and WooCommerce Notifications v2.0.9
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.0.9, at spoki.php

790 lines 29.4 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: Add WhatsApp chat button on your website and send WooCommerce status order notifications using WhatsApp!
5 * Version: 2.0.9
6 * Author: Reddoak Srl
7 * Author URI: https://reddoak.com
8 * Text Domain: spoki
9 * Domain Path: /languages
10 * License: GPLv2
11 */
12
13 define('SPOKI_DIR', plugin_dir_path(__FILE__));
14 include_once SPOKI_DIR . 'includes/constants.php';
15 include_once SPOKI_DIR . 'includes/spoki-functions.php';
16
17 add_filter( 'cron_schedules', 'add_cron_interval' );
18 function add_cron_interval( $schedules ) {
19 $schedules['every_day'] = array(
20 'interval' => 86400,
21 'display' => esc_html__( 'Every day' ), );
22 return $schedules;
23 }
24
25 $spoki = Spoki();
26
27 function Spoki()
28 {
29 return WpSpoki::instance();
30 }
31
32 final class WpSpoki
33 {
34 protected static $_instance = null;
35 private $version = '';
36 private $langs = '';
37 public $shop = [];
38
39 private $api_plan = SPOKI_BASE_API . "plan/";
40 private $api_status = SPOKI_BASE_API . "status/";
41 private $api_enable_flex = SPOKI_BASE_API . "enable/";
42 private $api_account = SPOKI_BASE_API . "account/";
43
44 public static function instance()
45 {
46 if (is_null(self::$_instance)) {
47 self::$_instance = new self();
48 }
49 return self::$_instance;
50 }
51
52 private function __construct()
53 {
54 $data = get_file_data(__FILE__, array('ver' => 'Version', 'langs' => 'Domain Path'));
55 $this->version = $data['ver'];
56 $this->langs = $data['langs'];
57 $this->options = get_option(SPOKI_OPTIONS);
58 $this->shop = [
59 "name" => isset($this->options['shop_name']) ? $this->options['shop_name'] : get_bloginfo('name'),
60 "url" => get_bloginfo('url'),
61 "email" => isset($this->options['email']) ? $this->options['email'] : get_bloginfo('admin_email'),
62 "language" => isset($this->options['language']) ? $this->options['language'] : get_bloginfo('language'),
63 "telephone" => isset($this->options['telephone']) ? $this->options['telephone'] : '',
64 "contact_link" => isset($this->options['account_info']['contact_link']) ? $this->options['account_info']['contact_link'] : null,
65 ];
66
67 add_action('init', 'spoki_update_po_file');
68 add_action('admin_menu', array($this, 'add_option_menu'));
69 add_filter("plugin_action_links_" . plugin_basename(__FILE__), array($this, 'plugin_settings_link'));
70 add_action('wp_enqueue_scripts', array($this, 'add_styles'));
71 add_action('admin_enqueue_scripts', array($this, 'add_admin_styles'));
72 add_action('updated_option', array($this, 'on_option_added'), 10, 3);
73 add_action('spoki_cron_hook', array($this, 'check_secret_status'));
74
75 if ( !wp_next_scheduled( 'spoki_cron_hook' ) ) {
76 $this->check_secret_status();
77 wp_schedule_event( time(), 'every_day', 'spoki_cron_hook' );
78 }
79
80 $this->includes();
81 $this->handle_woocommerce();
82 $this->render_buttons();
83 }
84
85 /**
86 * Include all Spoki required files
87 */
88 private function includes()
89 {
90 require_once SPOKI_DIR . 'includes/spoki-functions.php';
91 }
92
93 /**
94 * Get the setting link of the plugin
95 *
96 * @param $links
97 * @return mixed
98 */
99 public function plugin_settings_link($links)
100 {
101 $settings_link = '<a href="options-general.php?page=' . SPOKI_PLUGIN_NAME . '">' . __('Settings', SPOKI_PLUGIN_NAME) . '</a>';
102 array_unshift($links, $settings_link);
103 return $links;
104 }
105
106 /**
107 * Add the Spoki option to the menu
108 */
109 public function add_option_menu()
110 {
111 add_menu_page(
112 'Spoki Options',
113 'Spoki',
114 'manage_options',
115 'spoki',
116 array($this, 'render_setup_page'),
117 plugins_url() . '/' . SPOKI_PLUGIN_NAME . '/assets/images/logo.svg',
118 98
119 );
120 add_action('admin_init', array($this, 'register_option_var'));
121 }
122
123 /**
124 * Register the Spoki option
125 */
126 public function register_option_var()
127 {
128 register_setting('wp-spoki-option', SPOKI_OPTIONS);
129 }
130
131 /**
132 * Add website spoki styles
133 */
134 public function add_styles()
135 {
136 $styles = ['buttons'];
137 foreach ($styles as $style) {
138 echo "<style id='spoki-style-$style'>";
139 include SPOKI_DIR . "assets/css/$style.css";
140 echo "</style>";
141 }
142 }
143
144 /**
145 * Add admin spoki styles
146 */
147 public function add_admin_styles()
148 {
149 $styles = ['admin.css', 'onboarding.css', 'account-overview.css', 'spoki-overview.css'];
150
151 foreach ($styles as $style) {
152 echo "<style>";
153 include_once SPOKI_DIR . 'assets/css/' . $style;
154 echo "</style>";
155 }
156 }
157
158 /**
159 * Handle option submit
160 *
161 * @param $option
162 * @param $old_value
163 * @param $value
164 */
165 public function on_option_added($option, $old_value, $value)
166 {
167 if ($option == SPOKI_OPTIONS) {
168
169 /** New Telephone from settings */
170 if (isset($value['telephone'])) {
171 $this->update_options($value, ["telephone" => spoki_get_formatted_telephone($value['telephone'])]);
172 }
173
174 /** Onboarding Without WooCommerce */
175 if (isset($value['onboarding']['without_wc'])) {
176 $this->update_options($value, [
177 "telephone" => spoki_get_formatted_telephone($value['onboarding']['telephone']),
178 "onboarding" => null,
179 ]);
180 $url = admin_url('/admin.php?page=' . SPOKI_PLUGIN_NAME . '&tab=' . urlencode('Floating Button'));
181 header("Location: {$url}");
182 exit;
183 }
184
185 /** Onboarding With WooCommerce */
186 if (isset($value['onboarding']['with_wc'])) {
187 $response = $this->create_spoki_account($value['onboarding']['telephone'], $value['onboarding']['email'], $value['onboarding']['shop_name']);
188 if (isset($response['secret']) && isset($response['delivery_url'])) {
189 $this->update_options($value, [
190 "telephone" => spoki_get_formatted_telephone($value['onboarding']['telephone']),
191 "email" => $value['onboarding']['email'],
192 "shop_name" => $value['onboarding']['shop_name'],
193 "secret" => $response['secret'],
194 "delivery_url" => $response['delivery_url'],
195 "onboarding" => null,
196 "woocommerce" => [
197 "order_created" => 1,
198 "order_updated" => 1,
199 "order_deleted" => 1,
200 "order_note_added" => 1,
201 ],
202 ]);
203 $url = admin_url('/admin.php?page=' . SPOKI_PLUGIN_NAME . '&tab=' . urlencode('WooCommerce'));
204 header("Location: {$url}");
205 exit;
206 }
207 }
208
209 /** Settings updated for registered account */
210 if (isset($value['is_settings'])) {
211 $keys_changed = ($value['secret'] != $old_value['secret']) || ($value['delivery_url'] != $old_value['delivery_url']);
212
213 $shop_name_changed = $value['shop_name'] != $old_value['shop_name'];
214 $email_changed = $value['email'] != $old_value['email'];
215 $telephone_changed = $value['telephone'] != $old_value['telephone'];
216 $contact_link_changed = $value['contact_link'] != $old_value['contact_link'];
217 $billing_data_changed = $value['billing_data'] != $old_value['billing_data'];
218
219 if ($shop_name_changed || $email_changed || $telephone_changed || $contact_link_changed || $billing_data_changed) {
220 $this->update_spoki_account($value['telephone'], $value['email'], $value['shop_name'], $value['contact_link'], $value['billing_data']);
221 }
222
223 if ($keys_changed) {
224 $url = admin_url('/admin.php?page=' . SPOKI_PLUGIN_NAME . '&tab=' . urlencode('Welcome'));
225 header("Location: {$url}");
226 exit;
227 }
228 }
229 }
230 }
231
232 /**
233 * Handle WooCommerce features
234 */
235 public function handle_woocommerce()
236 {
237 if (isset($this->options['secret'])) {
238 include_once(ABSPATH . 'wp-admin/includes/plugin.php');
239 if (is_plugin_active('woocommerce/woocommerce.php')) {
240 if (isset($this->options['woocommerce']['order_updated']) && $this->options['woocommerce']['order_updated'] == 1) {
241 add_action('woocommerce_order_status_changed', array($this, 'send_woocommerce_order_updated_alert'), 10, 3);
242 }
243 if (isset($this->options['woocommerce']['order_created']) && $this->options['woocommerce']['order_created'] == 1) {
244 add_action('woocommerce_checkout_order_created', array($this, 'send_woocommerce_order_created_alert'), 10, 3);
245 }
246 if (isset($this->options['woocommerce']['order_deleted']) && $this->options['woocommerce']['order_deleted'] == 1) {
247 add_action('woocommerce_cancelled_order', array($this, 'send_woocommerce_order_deleted_alert'), 10, 3);
248 add_action('woocommerce_trash_order', array($this, 'send_woocommerce_order_deleted_alert'), 10, 3);
249 }
250 // TODO
251 // if (isset($this->options['woocommerce']['cart_abandoned']) && $this->options['woocommerce']['cart_abandoned'] == 1) {
252 // add_action('woocommerce_ajax_added_to_cart', array($this, 'send_woocommerce_order_alert'), 10, 3);
253 // }
254 if (isset($this->options['woocommerce']['order_note_added']) && $this->options['woocommerce']['order_note_added'] == 1) {
255 add_action('woocommerce_order_note_added', array($this, 'send_woocommerce_note_alert'), 10, 2);
256 }
257
258 if (isset($this->options['woocommerce']['cart_button_hide_checkout_button_check']) && $this->options['woocommerce']['cart_button_hide_checkout_button_check'] == 1) {
259 add_action('woocommerce_proceed_to_checkout', array($this, 'disable_checkout_button'), 1);
260 }
261 }
262 }
263 $this->fetch_secret_status();
264 }
265
266 /**
267 * Send the Spoki notification for order status updated
268 *
269 * @param $order_get_id
270 */
271 public function send_woocommerce_order_updated_alert($order_get_id)
272 {
273 $this->send_woocommerce_order_alert($order_get_id, 'order.updated');
274 }
275
276 /**
277 * Send the Spoki notification for order created
278 *
279 * @param $order_get_id
280 */
281 public function send_woocommerce_order_created_alert($order_get_id)
282 {
283 $this->send_woocommerce_order_alert($order_get_id, 'order.created');
284 }
285
286 /**
287 * Send the Spoki notification for order deleted
288 *
289 * @param $order_get_id
290 */
291 public function send_woocommerce_order_deleted_alert($order_get_id)
292 {
293 $this->send_woocommerce_order_alert($order_get_id, 'order.updated');
294 }
295
296 /**
297 * Send the Spoki notification for order status
298 *
299 * @param $order_get_id
300 */
301 public function send_woocommerce_order_alert($order_get_id, $target)
302 {
303 $order = wc_get_order($order_get_id);
304 $shop = ["shop" => $this->shop];
305 $order_data = (isset($order) && false != $order ? $order->get_data() : ["id" => $order_get_id]);
306 $this->spoki_send(array_merge($order_data, $shop), $target);
307 }
308
309 /**
310 * Send the Spoki notification for tracking number
311 *
312 * @param $id
313 * @param $order
314 */
315 public function send_woocommerce_note_alert($id, $order)
316 {
317 $comment = get_comment($id);
318
319 if (isset($comment->comment_content)) {
320 $is_gls_tracking = substr(strtolower($comment->comment_content), 0, 4) == '[gls';
321 $is_user_tracking = substr(strtolower($comment->comment_content), 0, 10) == '[tracking]';
322
323 /** Send the message only if it is a tracking order note */
324 if ($comment->comment_type == 'order_note' && ($is_gls_tracking || $is_user_tracking)) {
325 $order_data = $order->get_data();
326 $shop = ["shop" => $this->shop];
327 $note = ["note" => $comment];
328 $this->spoki_send(array_merge($order_data, $shop, $note), 'order.tracking');
329 }
330 }
331 }
332
333 /**
334 * Send the Spoki notification
335 *
336 * @param $data
337 * @return bool
338 */
339 private function spoki_send($data, $topic): bool
340 {
341 $request_params = array(
342 "headers" => array(
343 "Authorization" => $this->options['secret'],
344 "language" => $this->shop['language'],
345 "X-Wc-Webhook-Topic" => $topic,
346 ),
347 "body" => wp_json_encode($data)
348 );
349 $response = wp_remote_post($this->options['delivery_url'], $request_params);
350 $code = wp_remote_retrieve_response_code($response);
351 return $code == 200;
352 }
353
354 /**
355 * Create a new Spoki Free account
356 *
357 * @param $telephone
358 * @param $email
359 * @param $shop_name
360 * @return array
361 */
362 private function create_spoki_account($telephone, $email, $shop_name): array
363 {
364 $request_params = array(
365 "headers" => array("Authorization" => $this->options['secret'], "language" => $this->shop['language']),
366 "body" => [
367 "phone" => $telephone,
368 "email" => $email,
369 "name" => $shop_name,
370 ],
371 );
372
373 $response = wp_remote_post($this->api_enable_flex, $request_params);
374 $code = wp_remote_retrieve_response_code($response);
375
376 if ($code >= 200 && $code < 300) {
377 $data = json_decode(wp_remote_retrieve_body($response), true);
378 return [
379 "secret" => isset($data['secret']) ? $data['secret'] : null,
380 "delivery_url" => isset($data['delivery_url']) ? $data['delivery_url'] : null,
381 ];
382 }
383 return [];
384 }
385
386
387 /**
388 * Update a Spoki account
389 *
390 * @param $telephone
391 * @param $email
392 * @param $shop_name
393 * @param $contact_link
394 * @param $billing_data
395 */
396 private function update_spoki_account($telephone, $email, $shop_name, $contact_link, $billing_data = [])
397 {
398 $request_params = array(
399 "headers" => array("Authorization" => $this->options['secret'], "language" => $this->shop['language']),
400 "body" => [
401 "phone" => $telephone ?: '',
402 "email" => $email ?: '',
403 "name" => $shop_name ?: '',
404 "contact_link" => $contact_link ?: '',
405 "zip_code" => $billing_data['zip_code'] ?: '',
406 "province" => $billing_data['province'] ?: '',
407 "country" => $billing_data['country'] ?: '',
408 "route" => $billing_data['route'] ?: '',
409 "city" => $billing_data['city'] ?: '',
410 "vat_number" => $billing_data['vat_number'] ?: '',
411 "vat_name" => $billing_data['vat_name'] ?: '',
412 "c_f" => $billing_data['c_f'] ?: '',
413 "pec" => $billing_data['pec'] ?: '',
414 "sid" => $billing_data['sid'] ?: '',
415 ],
416 );
417 wp_remote_post($this->api_account, $request_params);
418 }
419
420 /**
421 * Fetch and update the account_info
422 */
423 public function fetch_account_info()
424 {
425 $request_params = array("headers" => array("Authorization" => $this->options['secret'], "language" => $this->shop['language']));
426 $response = wp_remote_get($this->api_plan, $request_params);
427 $this->update_options(get_option(SPOKI_OPTIONS), ["account_info" => json_decode(wp_remote_retrieve_body($response), true)]);
428 }
429
430 /**
431 * Check the status of the spoki keys
432 *
433 * @return array|WP_Error
434 */
435 public function check_spoki_status()
436 {
437 $secret = isset($this->options['secret']) ? $this->options['secret'] : null;
438 $request_params = array("headers" => array("Authorization" => $secret, "language" => $this->shop['language']));
439 $response = wp_remote_get($this->api_status, $request_params);
440 return $response;
441 }
442
443 /**
444 * Render the admin setup page
445 */
446 public function render_setup_page()
447 {
448 require_once SPOKI_DIR . 'includes/page-setup.php';
449 }
450
451 /**
452 * Render the WhatsApp buttons in the website
453 */
454 public function render_buttons()
455 {
456 $has_fixed_support_button = isset($this->options['buttons']['fixed_support_button_check']) && $this->options['buttons']['fixed_support_button_check'] == 1;
457 $has_product_item_listing_button = isset($this->options['woocommerce']['product_item_listing_button_check']) && $this->options['woocommerce']['product_item_listing_button_check'] == 1;
458 $has_cart_button = isset($this->options['woocommerce']['cart_button_check']) && $this->options['woocommerce']['cart_button_check'] == 1;
459 $has_single_product_button = isset($this->options['woocommerce']['single_product_button_check']) && $this->options['woocommerce']['single_product_button_check'] == 1;
460
461 // Floating Button
462 if ($has_fixed_support_button) {
463 add_action('wp_footer', array($this, 'render_floating_button'), 1);
464 }
465
466 // Product Item Listing Button
467 if ($has_product_item_listing_button) {
468 add_action('woocommerce_after_shop_loop_item', array($this, 'render_product_item_listing_button'), 20);
469 }
470
471 // Cart Page Button
472 if ($has_cart_button) {
473 add_action('woocommerce_after_cart_totals', array($this, 'render_cart_button'), 20);
474 }
475
476 // Single Product Page Button
477 if ($has_single_product_button) {
478 $position = isset($this->options['woocommerce']['single_product_button_position']) ? $this->options['woocommerce']['single_product_button_position'] : 'after_atc';
479 switch ($position) {
480 case 'under_atc':
481 add_action('woocommerce_after_add_to_cart_form', array($this, 'render_single_product_button'), 5);
482 break;
483 case 'after_shortdesc':
484 add_action('woocommerce_before_add_to_cart_form', array($this, 'render_single_product_button'), 5);
485 break;
486 case 'after_atc':
487 default:
488 add_action('woocommerce_after_add_to_cart_button', array($this, 'render_single_product_button'), 5);
489 break;
490 }
491 }
492
493 if ($has_fixed_support_button || $has_product_item_listing_button || $has_cart_button || $has_single_product_button) {
494 add_action('wp_footer', array($this, 'render_shadowed_buttons'));
495 }
496 }
497
498 public function disable_checkout_button() {
499 remove_action( 'woocommerce_proceed_to_checkout', 'woocommerce_button_proceed_to_checkout', 20 );
500 }
501
502 /**
503 *
504 */
505 public function render_shadowed_buttons()
506 {
507 echo "<script>(() => Array.from(document.getElementsByClassName('spoki-shadowed-button')).forEach(el => {
508 const content = document.importNode(el, true);
509 const shadowRoot = el.attachShadow({mode: 'closed'});
510 el.innerHTML = '';
511 const style = document.createElement('style');
512 style.innerHTML = document.getElementById('spoki-style-buttons').innerHTML.replace(/(\\r\\n|\\n|\\r)/gm, '');
513 shadowRoot.appendChild(style);
514 shadowRoot.appendChild(content.firstChild);
515 }))();</script>";
516 }
517
518 /**
519 * Render the WhatsApp FAB on the website in every page
520 */
521 public function render_floating_button()
522 {
523 if (isset($this->options['telephone']) && $this->options['telephone'] != '') {
524 $phone = $this->options['telephone'];
525 $text = $this->options['buttons']['fixed_support_button_text'];
526 $position = $this->options['buttons']['fixed_support_button_position'] == 'Left' ? 'left' : 'right';
527 $border_type = isset($this->options['buttons']['fixed_support_button_border']) ? $this->options['buttons']['fixed_support_button_border'] : 'circle';
528 $border_radius = '50%';
529 if ($border_type == 'squared') {
530 $border_radius = '0';
531 } elseif ($border_type == 'rounded') {
532 $border_radius = '8px';
533 }
534 $color = isset($this->options['buttons']['fixed_support_button_color']) ? $this->options['buttons']['fixed_support_button_color'] : '#23D366';
535 $bottom_space = isset($this->options['buttons']['fixed_support_button_bottom_space']) ? $this->options['buttons']['fixed_support_button_bottom_space'] : '12';
536 $side_space = isset($this->options['buttons']['fixed_support_button_side_space']) ? $this->options['buttons']['fixed_support_button_side_space'] : '12';
537 $wa_link = "https://api.whatsapp.com/send/?phone=$phone&text=" . urlencode($text);
538 echo "<div id='spoki-shadowed-fixed-button' class='spoki-shadowed-button'><div id='spoki-fixed-btn' style='$position:{$side_space}px;bottom:{$bottom_space}px;'><a id='spoki-chat-link' style='background-color:{$color};border-radius:$border_radius;' href='$wa_link' target='_blank'><img alt='WhatsApp logo' src='https://app.spoki.it/static/png/whatsapp-logo-squared.png'/></a></div></div>";
539 }
540 }
541
542 /**
543 * Render the product button for every product in shop page
544 */
545 public function render_product_item_listing_button()
546 {
547 global $product;
548 $phone = $this->options['telephone'];
549 $cta = __("Request support on WhatsApp", "spoki");
550 if (isset($this->options['woocommerce']['product_item_listing_button_cta']) && !empty($this->options['woocommerce']['product_item_listing_button_cta'])) {
551 $cta = $this->options['woocommerce']['product_item_listing_button_cta'];
552 }
553 $message = __("Hi, I want to buy:", "spoki");
554 if (isset($this->options['woocommerce']['product_item_listing_button_text']) && !empty($this->options['woocommerce']['product_item_listing_button_text'])) {
555 $message = $this->options['woocommerce']['product_item_listing_button_text'];
556 }
557 $color = isset($this->options['woocommerce']['product_item_listing_button_color']) ? $this->options['woocommerce']['product_item_listing_button_color'] : '#23D366';
558 $margin_top = isset($this->options['woocommerce']['product_item_listing_button_margin_top']) ? $this->options['woocommerce']['product_item_listing_button_margin_top'] : '4';
559 $margin_bottom = isset($this->options['woocommerce']['product_item_listing_button_margin_bottom']) ? $this->options['woocommerce']['product_item_listing_button_margin_bottom'] : '4';
560 $border_type = isset($this->options['woocommerce']['product_item_listing_button_border']) ? $this->options['woocommerce']['product_item_listing_button_border'] : 'rounded';
561
562 $this->render_product_button($product, $phone, $cta, $message, $color, $border_type, $margin_top, $margin_bottom);
563 }
564
565 /**
566 * Render the button in the cart page
567 */
568 public function render_cart_button()
569 {
570 global $product;
571 $phone = $this->options['telephone'];
572 $cta = __("Order via WhatsApp", "spoki");
573 if (isset($this->options['woocommerce']['cart_button_cta']) && !empty($this->options['woocommerce']['cart_button_cta'])) {
574 $cta = $this->options['woocommerce']['cart_button_cta'];
575 }
576 $message = __("Hi, I want to buy:", "spoki");
577 if (isset($this->options['woocommerce']['cart_button_text']) && !empty($this->options['woocommerce']['cart_button_text'])) {
578 $message = $this->options['woocommerce']['cart_button_text'];
579 }
580 $color = isset($this->options['woocommerce']['cart_button_color']) ? $this->options['woocommerce']['cart_button_color'] : '#23D366';
581 $margin_top = isset($this->options['woocommerce']['cart_button_margin_top']) ? $this->options['woocommerce']['cart_button_margin_top'] : '4';
582 $margin_bottom = isset($this->options['woocommerce']['cart_button_margin_bottom']) ? $this->options['woocommerce']['cart_button_margin_bottom'] : '4';
583
584 $final_message = urlencode($message);
585
586 $products = WC()->cart->get_cart();
587
588 foreach ($products as $item) {
589 $product_id = $item['product_id'];
590 $qty = $item['quantity'];
591 $product = wc_get_product($product_id);
592 $product_url = $product->get_permalink();
593 $product_title = $product->get_name();
594 $price = wp_strip_all_tags(wc_price(wc_get_price_including_tax($product)));
595 $encoded_title = urlencode($product_title);
596 $encoded_product_url = urlencode($product_url);
597 $final_message .= "%0D%0A%0D%0A(ID:%20$product_id)%20*$encoded_title*%20$price%20x$qty%0D%0A$encoded_product_url";
598 }
599
600 $href = "https://api.whatsapp.com/send?phone=$phone&text=$final_message";
601 $title = "$cta";
602 $class = 'button spoki-button size-4';
603 $border_type = isset($this->options['woocommerce']['cart_button_border']) ? $this->options['woocommerce']['cart_button_border'] : 'rounded';
604
605 $border_radius = '16px';
606 if ($border_type == 'squared') {
607 $border_radius = '0';
608 }
609
610 echo "<div class='spoki-shadowed-button'><div class='spoki-button-relative' style='margin-top:{$margin_top}px;margin-bottom:{$margin_bottom}px'><a href='$href' target='_blank' title='$title' class='$class' style='background-color:$color;border-radius:$border_radius'><img class='spoki-wa-icon' alt='WhatsApp logo' src='https://app.spoki.it/static/png/whatsapp-logo-squared.png'/><span>$cta</span></a></div></div>";
611 }
612
613 /**
614 * Render the button in the product page
615 */
616 public function render_single_product_button()
617 {
618 global $product;
619 $phone = $this->options['telephone'];
620 $cta = __("Request support on WhatsApp", "spoki");
621 if (isset($this->options['woocommerce']['single_product_button_cta']) && !empty($this->options['woocommerce']['single_product_button_cta'])) {
622 $cta = $this->options['woocommerce']['single_product_button_cta'];
623 }
624 $message = __("Hi, I want to buy:", "spoki");
625 if (isset($this->options['woocommerce']['single_product_button_text']) && !empty($this->options['woocommerce']['single_product_button_text'])) {
626 $message = $this->options['woocommerce']['single_product_button_text'];
627 }
628 $position = isset($this->options['woocommerce']['single_product_button_position']) ? $this->options['woocommerce']['single_product_button_position'] : 'after_atc';
629 $color = isset($this->options['woocommerce']['single_product_button_color']) ? $this->options['woocommerce']['single_product_button_color'] : '#23D366';
630 $margin_top = isset($this->options['woocommerce']['single_product_button_margin_top']) ? $this->options['woocommerce']['single_product_button_margin_top'] : '4';
631 $margin_bottom = isset($this->options['woocommerce']['single_product_button_margin_bottom']) ? $this->options['woocommerce']['single_product_button_margin_bottom'] : '4';
632 $border_type = isset($this->options['woocommerce']['single_product_button_border']) ? $this->options['woocommerce']['single_product_button_border'] : 'rounded';
633
634 $this->render_product_button($product, $phone, $cta, $message, $color, $border_type, $margin_top, $margin_bottom, $position);
635 }
636
637 /**
638 * Render the button of a product
639 *
640 * @param $product
641 * @param $phone
642 * @param $cta
643 * @param $message
644 * @param null $position
645 */
646 public function render_product_button($product, $phone, $cta, $message, $color = '#23D366', $border_type = 'rounded', $margin_top = '4', $margin_bottom = '4', $position = null)
647 {
648 $product_url = $product->get_permalink();
649 $product_title = $product->get_name();
650 $product_id = $product->get_id();
651
652 $class = sprintf('button spoki-button product_type_%s', $product->get_type());
653 if (isset($position)) {
654 $class .= " size-2 $position";
655 } else {
656 $class .= " size-4";
657 }
658 $price = wp_strip_all_tags(wc_price(wc_get_price_including_tax($product)));
659
660 $border_radius = '16px';
661 if ($border_type == 'squared') {
662 $border_radius = '0';
663 }
664
665 $encoded_message = urlencode($message);
666 $encoded_title = urlencode($product_title);
667 $encoded_product_url = urlencode($product_url);
668
669 $final_message = "$encoded_message%0D%0A%0D%0A(ID:%20$product_id)%20*$encoded_title*%20$price%0D%0A$encoded_product_url";
670 $href = "https://api.whatsapp.com/send?phone=$phone&text=$final_message";
671 $title = "$cta $product_title";
672
673 echo "<div class='spoki-shadowed-button'><div class='spoki-button-relative' style='margin-top:{$margin_top}px;margin-bottom:{$margin_bottom}px;'><a href='$href' target='_blank' title='$title' class='$class' style='background-color:$color;border-radius:$border_radius'><img class='spoki-wa-icon' alt='WhatsApp logo' src='https://app.spoki.it/static/png/whatsapp-logo-squared.png'/><span>$cta</span></a></div></div>";
674 }
675
676 /**
677 * Get the link to change plan
678 *
679 * @param $is_upgrade
680 * @return string
681 */
682 public function get_plan_link($is_upgrade): string
683 {
684 $url = $this->shop['language'] == 'it-IT' ? 'https://spoki.it/spoki-flex-acquista-pacchetti-flex/?' : 'https://spoki.it/spoki-flex-acquista-pacchetti-flex/spoki-flex-packages/?';
685
686 if (isset($this->options['account_info']['upgrade_url']) ? $this->options['account_info']['upgrade_url'] : '') {
687 $url = $this->options['account_info']['upgrade_url'];
688 }
689 if ($is_upgrade) {
690 $url .= '&is_upgrade=true';
691 }
692 return $url;
693 }
694
695 /**
696 * Update Spoki options
697 *
698 * @param $current_options
699 * @param $new_options
700 */
701 private function update_options($current_options, $new_options)
702 {
703 $c_options = is_string($current_options) ? [] : $current_options;
704 if (isset($new_options["woocommerce"])) {
705 $woocommerce = array_merge($c_options["woocommerce"], $new_options["woocommerce"]);
706 $new_options["woocommerce"] = $woocommerce;
707 }
708 update_option(SPOKI_OPTIONS, array_merge($c_options, $new_options));
709 $this->options = get_option(SPOKI_OPTIONS);
710 }
711
712 /**
713 * Check the secret status periodically
714 */
715 public function check_secret_status()
716 {
717 $this->fetch_secret_status(true);
718 }
719
720 /**
721 * Fetch the status of the Spoki keys
722 */
723 public function fetch_secret_status($force_checking = false)
724 {
725 $response = null;
726 if ($force_checking) {
727 $response = $this->check_spoki_status();
728 }
729
730 if (!isset($this->options['secret']) || $this->options['secret'] == '' || !isset($this->options['delivery_url']) || $this->options['delivery_url'] == '') {
731 $this->update_options(get_option(SPOKI_OPTIONS), ["secret_status" => [
732 'secret' => isset($this->options['secret']) ? $this->options['secret'] : '',
733 'delivery_url' => isset($this->options['delivery_url']) ? $this->options['delivery_url'] : '',
734 'code' => 0,
735 'message' => ''
736 ]]);
737 } 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']) {
738 if (!$force_checking) {
739 $response = $this->check_spoki_status();
740 }
741 $this->update_options(get_option(SPOKI_OPTIONS), ["secret_status" => [
742 'secret' => isset($this->options['secret']) ? $this->options['secret'] : '',
743 'delivery_url' => isset($this->options['delivery_url']) ? $this->options['delivery_url'] : '',
744 'code' => wp_remote_retrieve_response_code($response),
745 'message' => wp_remote_retrieve_response_message($response)
746 ]]);
747 }
748 }
749 }
750
751 /**
752 * Executed on activation of the plugin
753 */
754 function spoki_activation() {
755 // Don't do redirects when multiple plugins are bulk activated
756 if (
757 ( isset( $_REQUEST['action'] ) && 'activate-selected' === $_REQUEST['action'] ) &&
758 ( isset( $_POST['checked'] ) && count( $_POST['checked'] ) > 1 ) ) {
759 return;
760 }
761 add_option( 'spoki_activation_redirect', wp_get_current_user()->ID );
762 }
763
764 /**
765 * Redirects the user after plugin activation.
766 */
767 function spoki_activation_redirect() {
768 // Make sure it's the correct user
769 if ( intval( get_option( 'spoki_activation_redirect', false ) ) === wp_get_current_user()->ID ) {
770 // Make sure we don't redirect again after this one
771 delete_option( 'spoki_activation_redirect' );
772 wp_safe_redirect( admin_url( '/options-general.php?page=' . SPOKI_PLUGIN_NAME ) );
773 exit;
774 }
775 }
776
777 /**
778 * Executed on deactivation of the plugin
779 */
780 function spoki_deactivation()
781 {
782 // delete_option(SPOKI_OPTIONS);
783 $timestamp = wp_next_scheduled( 'spoki_cron_hook' );
784 wp_unschedule_event( $timestamp, 'spoki_cron_hook' );
785 }
786
787 register_deactivation_hook( __FILE__, 'spoki_deactivation' );
788 // register_activation_hook( __FILE__, 'spoki_activation' );
789 // add_action( 'admin_init', 'spoki_activation_redirect' );
790