PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / 3.2.7
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar v3.2.7
3.3.3 3.3.2 3.3.1 3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 trunk 0.2.5.5 0.2.5.6 0.2.5.7 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 All 158 releases
notificationx / includes / Extensions / FluentCart / FluentCart.php

FluentCart.php in NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar 3.2.7, at includes/Extensions/FluentCart/FluentCart.php

725 lines 28.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * FluentCart Extension
4 *
5 * @package NotificationX\Extensions
6 */
7
8 namespace NotificationX\Extensions\FluentCart;
9 use NotificationX\GetInstance;
10 use NotificationX\Extensions\Extension;
11 use NotificationX\Extensions\GlobalFields;
12 use NotificationX\Admin\Entries;
13 use NotificationX\Core\Helper;
14 use NotificationX\Core\Rules;
15
16 /**
17 * FluentCart Extension Class
18 * @method static FluentCart get_instance($args = null)
19 */
20 class FluentCart extends Extension {
21 use GetInstance;
22 public $priority = 8;
23 public $id = 'fluentcart';
24 public $doc_link = 'https://notificationx.com/docs/fluentcart-sales-notifications/';
25 public $types = 'conversions';
26 public $img = NOTIFICATIONX_ADMIN_URL . 'images/extensions/sources/fluentcart.png';
27 public $module = 'modules_fluentcart';
28 public $module_priority = 35;
29 public $class = '\FluentCart\Framework\Foundation\App';
30 public $post_type = 'fluent-products';
31
32 /**
33 * Initially Invoked when initialized.
34 */
35 public function __construct(){
36 parent::__construct();
37 }
38
39 public function init_extension()
40 {
41 $this->title = __('FluentCart', 'notificationx');
42 $this->module_title = __('FluentCart', 'notificationx');
43 }
44
45 public function init(){
46 parent::init();
47 add_action('fluent_cart/order_paid_done', array( $this, 'save_new_records'), 10, 1);
48 add_action('fluent_cart/order_created', array( $this, 'save_new_records'), 10, 1);
49 add_action('fluent_cart/payment_status_changed', [$this, 'status_transition'], 10, 1);
50 add_action('fluent_cart/order_status_changed', [$this, 'status_transition'], 10, 1);
51 }
52
53 public function init_fields(){
54 parent::init_fields();
55 add_filter('nx_link_types', [$this, 'link_types']);
56 add_filter( 'nx_fluentcart_order_status', array( $this, 'order_status' ), 11 );
57 add_filter("nx_notification_link_{$this->id}", [$this, 'product_link'], 10, 3);
58 add_filter('nx_conversion_category_list', [$this, 'collections']);
59 add_filter('nx_conversion_product_list', [$this, 'product_lists']);
60
61 }
62
63 /**
64 * This functions is hooked
65 *
66 * @return void
67 */
68 public function admin_actions() {
69 parent::admin_actions();
70 add_filter("nx_can_entry_{$this->id}", array($this, 'nx_can_entry'), 10, 3);
71 }
72
73 public function public_actions(){
74 parent::public_actions();
75 }
76
77 public function nx_can_entry($return, $entry, $settings){
78 // Default to 'paid' and 'processing' if no status is specified
79 $allowed_statuses = !empty($settings['fluentcart_order_status']) ? $settings['fluentcart_order_status'] : ['paid', 'processing'];
80
81 // Check if any of the order's statuses match the allowed statuses
82 $status_matches = false;
83
84 // Check payment status
85 if (!empty($entry['data']['payment_status']) && in_array($entry['data']['payment_status'], $allowed_statuses)) {
86 $status_matches = true;
87 }
88
89 // Check order status
90 if (!empty($entry['data']['status']) && in_array($entry['data']['status'], $allowed_statuses)) {
91 $status_matches = true;
92 }
93
94 // Check shipping status
95 if (!empty($entry['data']['shipping_status']) && in_array($entry['data']['shipping_status'], $allowed_statuses)) {
96 $status_matches = true;
97 }
98
99 // Check fulfillment status (FluentCart specific)
100 if (!empty($entry['data']['fulfillment_status']) && in_array($entry['data']['fulfillment_status'], $allowed_statuses)) {
101 $status_matches = true;
102 }
103
104 // Return the original return value if status matches, otherwise return false
105 return $status_matches ? $return : false;
106 }
107
108 public function product_lists($products) {
109 $all_products = \FluentCart\App\Models\Product::published()->get();
110 $product_lists = [];
111 if( ! is_wp_error( $all_products ) && $all_products->count() > 0 ) {
112 foreach( $all_products as $product ) {
113 $product_lists[ $product->post_name ] = $product->post_title;
114 }
115 }
116 $options = GlobalFields::get_instance()->normalize_fields($product_lists, 'source', $this->id, $products);
117 return $options;
118 }
119
120 public function collections($options) {
121 // Get FluentCart product categories using the product-categories taxonomy
122 $categories = get_terms([
123 'taxonomy' => 'product-categories',
124 'hide_empty' => false,
125 ]);
126
127 $category_list = [];
128 if (!is_wp_error($categories) && !empty($categories)) {
129 foreach ($categories as $category) {
130 $category_list[$category->slug] = $category->name;
131 }
132 }
133
134 $options = GlobalFields::get_instance()->normalize_fields($category_list, 'source', $this->id, $options);
135 return $options;
136 }
137
138 public function product_link($link, $post, $entry) {
139 if(!empty($entry['permalink']) && !empty( $post['link_type'] ) && $post['link_type'] === 'product_page' ){
140 $link = $entry['permalink'];
141 }
142 return $link;
143 }
144
145 public function order_status($options){
146 // Get FluentCart's native order and payment statuses
147 $order_status = [];
148
149 try {
150 // Check if FluentCart Status class is available
151 if (class_exists('\FluentCart\App\Helpers\Status')) {
152 // Get Order Statuses
153 $order_statuses = \FluentCart\App\Helpers\Status::getOrderStatuses();
154 foreach ($order_statuses as $key => $label) {
155 $order_status[$key] = $label;
156 }
157
158 // Get Payment Statuses
159 $payment_statuses = \FluentCart\App\Helpers\Status::getPaymentStatuses();
160 foreach ($payment_statuses as $key => $label) {
161 $order_status[$key] = $label . ' (' . __('Payment', 'notificationx') . ')';
162 }
163
164 // Get Shipping Statuses if available
165 $shipping_statuses = \FluentCart\App\Helpers\Status::getShippingStatuses();
166 foreach ($shipping_statuses as $key => $label) {
167 $order_status[$key] = $label . ' (' . __('Shipping', 'notificationx') . ')';
168 }
169
170 } else {
171 // Fallback to manual status list if FluentCart classes are not available
172 $order_status = [
173 // Order Statuses
174 'processing' => __( 'Processing','notificationx' ),
175 'completed' => __( 'Completed','notificationx' ),
176 'on-hold' => __( 'On Hold','notificationx' ),
177 'canceled' => __( 'Canceled','notificationx' ),
178 'failed' => __( 'Failed','notificationx' ),
179
180 // Payment Statuses
181 'pending' => __( 'Pending (Payment)','notificationx' ),
182 'paid' => __( 'Paid (Payment)','notificationx' ),
183 'partially_paid' => __( 'Partially Paid (Payment)','notificationx' ),
184 'payment_failed' => __( 'Failed (Payment)','notificationx' ),
185 'refunded' => __( 'Refunded (Payment)','notificationx' ),
186 'partially_refunded' => __( 'Partially Refunded (Payment)','notificationx' ),
187 'authorized' => __( 'Authorized (Payment)','notificationx' ),
188
189 // Shipping Statuses
190 'unfulfilled' => __( 'Unfulfilled (Shipping)','notificationx' ),
191 'fulfilled' => __( 'Fulfilled (Shipping)','notificationx' ),
192 'shipped' => __( 'Shipped (Shipping)','notificationx' ),
193 'delivered' => __( 'Delivered (Shipping)','notificationx' ),
194 ];
195 }
196 } catch (\Exception $e) {
197 // Fallback in case of any errors
198 $order_status = [
199 'processing' => __( 'Processing','notificationx' ),
200 'completed' => __( 'Completed','notificationx' ),
201 'paid' => __( 'Paid','notificationx' ),
202 'fulfilled' => __( 'Fulfilled','notificationx' ),
203 ];
204 }
205
206 $options = GlobalFields::get_instance()->normalize_fields( $order_status, 'source', $this->id, $options);
207 return $options;
208 }
209
210 public function save_new_records($data) {
211 $order = isset($data['order']) ? $data['order'] : null;
212 $customer = isset($data['customer']) ? $data['customer'] : null;
213
214 if (!$order || !$customer) {
215 return;
216 }
217
218 // Load order items
219 $order->load('order_items');
220
221 foreach ($order->order_items as $order_item) {
222 if (!empty($order_item)) {
223 $single_notifications = $this->prepare_order_data($order_item, $customer, [], $order);
224 $key = $order->id . '_' . $order_item->id;
225 $this->save([
226 'source' => $this->id,
227 'entry_key' => $key,
228 'data' => $single_notifications,
229 ], true);
230 }
231 }
232 }
233
234 public function save_order_created($data) {
235 // This can be used for order created events if needed
236 // For now, we'll focus on paid orders
237 return;
238 }
239
240 public function prepare_order_data( $order_item, $customer, $return = [], $order = null ) {
241 $address_fields = ['city','country','address_1','address_2','postcode'];
242 $customer_fields = ['first_name','last_name','email','full_name'];
243
244 // Get product information from order item
245 if( !empty( $order_item->post_title ) ) {
246 $return['title'] = $order_item->post_title;
247 }
248 if( !empty( $order_item->post_title ) ) {
249 $return['product_title'] = $order_item->post_title;
250 }
251 if( !empty( $order_item->post_id ) ) {
252 $return['product_id'] = $order_item->post_id;
253 // Get product permalink
254 $return['permalink'] = get_permalink($order_item->post_id);
255 // Get product image
256 $return['image_url'] = get_the_post_thumbnail_url($order_item->post_id, 'thumbnail');
257 }
258 if( !empty( $order_item->unit_price ) ) {
259 $return['price'] = $order_item->unit_price;
260 }
261 if( !empty( $order_item->quantity ) ) {
262 $return['quantity'] = $order_item->quantity;
263 }
264
265 // Get customer information
266 foreach ($customer_fields as $customer_field) {
267 if( !empty( $customer->{$customer_field} ) ) {
268 $return[$customer_field] = $customer->{$customer_field};
269 }
270 }
271
272 // Get address information from order if available
273 if ($order) {
274 $order->load('billing_address', 'shipping_address');
275 $address = $order->billing_address ?: $order->shipping_address;
276 if ($address) {
277 foreach ($address_fields as $address_field) {
278 if( !empty( $address->{$address_field} ) ) {
279 $return[$address_field] = $address->{$address_field};
280 }
281 }
282 }
283
284 // Order information
285 if( !empty( $order->id ) ) {
286 $return['order_id'] = $order->id;
287 }
288 if( !empty( $order->payment_status ) ) {
289 $return['payment_status'] = $order->payment_status;
290 }
291 if( !empty( $order->status ) ) {
292 $return['status'] = $order->status;
293 }
294 if( !empty( $order->shipping_status ) ) {
295 $return['shipping_status'] = $order->shipping_status;
296 }
297 if( !empty( $order->fulfillment_status ) ) {
298 $return['fulfillment_status'] = $order->fulfillment_status;
299 }
300 if( !empty( $order->fulfillment_type ) ) {
301 $return['fulfillment_type'] = $order->fulfillment_type;
302 }
303 if( !empty( $order->created_at ) ) {
304 $return['timestamp'] = $order->created_at;
305 }
306 if( !empty( $order->ip_address ) ) {
307 $return['ip'] = $order->ip_address;
308 }
309 }
310
311 return $return;
312 }
313
314 /**
315 * Image action callback
316 * @param array $image_data
317 * @param array $data
318 * @param stdClass $settings
319 * @return array
320 */
321 public function notification_image($image_data, $data, $settings) {
322 if (!$settings['show_default_image'] && $settings['show_notification_image'] === 'featured_image') {
323 if ( !empty( $data['image_url'] ) ) {
324 $image_data['url'] = $data['image_url'];
325 }
326 }
327 return $image_data;
328 }
329
330 public function saved_post($post, $data, $nx_id) {
331 $this->delete_notification(null, $nx_id);
332 $this->get_notification_ready($data);
333 }
334
335 public function get_notification_ready( $post = array() ) {
336 // Validate required parameters
337 if( empty( $post ) || empty( $post['nx_id'] ) ) {
338 return;
339 }
340
341 // Get orders based on settings
342 $orders = $this->get_orders( $post );
343 if ( is_array( $orders ) && ! empty( $orders ) ) {
344 $entries = [];
345 foreach ( $orders as $order ) {
346 // Ensure we have all required data
347 if( empty( $order['entry_key'] ) || empty( $order['updated_at'] ) ) {
348 continue;
349 }
350
351 $entries[] = [
352 'nx_id' => $post['nx_id'],
353 'source' => $this->id,
354 'entry_key' => $order['entry_key'], // Use the unique entry key we created
355 'data' => $order,
356 'updated_at' => Helper::mysql_time($order['updated_at']),
357 ];
358 }
359
360 // Only update if we have valid entries
361 if( !empty( $entries ) ) {
362 $this->update_notifications($entries);
363 }
364 }
365 }
366
367 public function status_transition($data) {
368 $order = isset($data['order']) ? $data['order'] : null;
369 $customer = isset($data['customer']) ? $data['customer'] : null;
370
371 if (!$order || !$customer) {
372 return $data;
373 }
374
375 // Find all entries for this order (there can be multiple for different order items)
376 // We need to search for entries that start with the order ID
377 $all_entries = Entries::get_instance()->get_entries(['source' => $this->id]);
378 $order_entries = [];
379
380 if (!empty($all_entries)) {
381 foreach ($all_entries as $entry) {
382 // Check if entry_key starts with order ID (format: order_id_item_id)
383 if (strpos($entry['entry_key'], $order->id . '_') === 0) {
384 $order_entries[] = $entry;
385 }
386 }
387 }
388
389 if (!empty($order_entries) && count($order_entries) > 0) {
390 $entries = [];
391 foreach ($order_entries as $existing_order) {
392 $update_data = !empty($existing_order) ? $existing_order : [];
393 if (empty($existing_order) || empty($order)) {
394 continue;
395 }
396
397 // Update status information
398 if (!empty($order->payment_status)) {
399 $update_data['data']['payment_status'] = $order->payment_status;
400 }
401 if (!empty($order->status)) {
402 $update_data['data']['status'] = $order->status;
403 }
404 if (!empty($order->shipping_status)) {
405 $update_data['data']['shipping_status'] = $order->shipping_status;
406 }
407
408 $entries[] = [
409 'nx_id' => $update_data['nx_id'],
410 'source' => $this->id,
411 'entry_key' => $existing_order['entry_key'], // Keep the original entry key
412 'data' => $update_data['data'],
413 'updated_at' => Helper::mysql_time($order->updated_at),
414 ];
415 }
416
417 // Delete old entries and add updated ones
418 foreach ($order_entries as $existing_order) {
419 $this->delete_notification($existing_order['entry_key'], $existing_order['nx_id']);
420 }
421 $this->update_notifications($entries);
422 }
423
424 return $data;
425 }
426
427 public function get_orders( $post = array() ) {
428 if( empty( $post ) ) {
429 return;
430 }
431
432 $dateFrom = !empty( $post['display_from'] ) ? date('Y-m-d',strtotime('-'.$post['display_from'].' days',time())) : '';
433 $dateTo = date('Y-m-d',strtotime('1 days',time()));
434 $amount = !empty( $post['display_last'] ) ? $post['display_last'] : 10;
435
436 $get_orders = \FluentCart\App\Models\Order::with(['customer', 'order_items', 'billing_address', 'shipping_address'])
437 ->orderBy('created_at', 'desc')
438 ->limit($amount)
439 ->get();
440
441 $orders = [];
442 if( $get_orders->count() > 0 ) {
443 foreach ($get_orders as $order) {
444 $createdAt = strtotime($order->created_at);
445 if ($createdAt >= strtotime($dateFrom) && $createdAt <= strtotime($dateTo)) {
446 if( !empty( $order->order_items ) && $order->order_items->count() > 0 ) {
447 foreach ($order->order_items as $order_item) {
448 // Get product categories for this order item
449 $categories = [];
450 if (!empty($order_item->post_id)) {
451 $product_categories = get_the_terms($order_item->post_id, 'product-categories');
452 if (!is_wp_error($product_categories) && !empty($product_categories)) {
453 $categories = $product_categories;
454 }
455 }
456
457 if(( $this->_excludes_product($order_item, $post, $categories) === $this->_show_purchaseof($order_item, $post, $categories))){
458 continue;
459 }
460
461 $make_orders = $this->prepare_order_data($order_item, $order->customer, [], $order);
462 $make_orders['order'] = $order->id;
463 $make_orders['order_item_id'] = $order_item->id;
464 $make_orders['entry_key'] = $order->id . '_' . $order_item->id;
465 $make_orders['updated_at'] = $order->updated_at;
466
467 $orders[] = $make_orders;
468 }
469 }
470 }
471 }
472 }
473
474 return $orders;
475 }
476
477 public function _excludes_product($order_item, $settings, $categories = []) {
478 if( !empty( $settings['product_exclude_by'] ) && $settings['product_exclude_by'] === 'none' ) {
479 if( !empty( $settings['product_control'] ) && $settings['product_control'] === 'none' ) {
480 return true;
481 }
482 return false;
483 }
484 // Check product list
485 if( $settings['product_exclude_by'] == 'manual_selection' && !empty( $settings['exclude_products'] ) && count( $settings['exclude_products'] ) > 0 ) {
486 foreach ( $settings['exclude_products'] as $__product ) {
487 $product_slug = get_post_field('post_name', $order_item->post_id);
488 if( $__product['value'] == $product_slug ) {
489 return true;
490 }
491 }
492 }
493 // Check category list
494 if( $settings['product_exclude_by'] == 'product_category' && !empty( $settings['exclude_categories'] ) && count( $settings['exclude_categories'] ) > 0 ) {
495 foreach ($categories as $category) {
496 if( in_array( $category->slug, $settings['exclude_categories'] ) ) {
497 return true;
498 }
499 }
500 }
501 return false;
502 }
503
504 public function _show_purchaseof($order_item, $settings, $categories = []) {
505 if( !empty( $settings['product_control'] ) && $settings['product_control'] === 'none' ) {
506 if( !empty( $settings['product_exclude_by'] ) && $settings['product_exclude_by'] === 'none' ) {
507 return false;
508 }
509 return true;
510 }
511 // Check product list
512 if( $settings['product_control'] == 'manual_selection' && !empty( $settings['product_list'] ) && count( $settings['product_list'] ) > 0 ) {
513 foreach ( $settings['product_list'] as $__product ) {
514 $product_slug = get_post_field('post_name', $order_item->post_id);
515 if( $__product['value'] == $product_slug ) {
516 return true;
517 }
518 }
519 return false;
520 }
521 // Check category list
522 if( $settings['product_control'] == 'product_category' && !empty( $settings['category_list'] ) && count( $settings['category_list'] ) > 0 ) {
523 foreach ($categories as $category) {
524 if( in_array( $category->slug, $settings['category_list'] ) ) {
525 return true;
526 }
527 }
528 return false;
529 }
530 return true;
531 }
532
533 /**
534 * Lists available FluentCart products for search functionality.
535 *
536 * @param array $args An array of arguments, including inputValue.
537 * @return array An indexed array of product IDs and titles.
538 */
539 public function restResponse($args) {
540 // Check if inputValue is provided or if we should return empty results
541 if ( empty( $args['search_empty']) && empty($args['inputValue'] ) ) {
542 return [];
543 }
544
545 // Use FluentCart's native search if available, otherwise fallback to WordPress search
546 $products = $this->search_fluentcart_products($args['inputValue']);
547
548 // If FluentCart search didn't work, fallback to WordPress post search
549 if (empty($products)) {
550 $products = Helper::get_post_titles_by_search($this->post_type, $args['inputValue']);
551 }
552
553 // Normalize the fields and return as an indexed array
554 return array_values(GlobalFields::get_instance()->normalize_fields($products, 'source', $this->id));
555 }
556
557 /**
558 * Search FluentCart products using FluentCart's native methods
559 *
560 * @param string $search_term The search term
561 * @return array Array of products with ID and title
562 */
563 private function search_fluentcart_products($search_term = '') {
564 $products = [];
565
566 try {
567 // Check if FluentCart is available
568 if (!class_exists('\FluentCart\App\Models\Product')) {
569 return $products;
570 }
571
572 // Use FluentCart's Product model to search
573 $query = \FluentCart\App\Models\Product::query()
574 ->where('post_status', 'publish');
575
576 // Add search condition if search term is provided
577 if (!empty($search_term)) {
578 $query->where(function($q) use ($search_term) {
579 // Search by product title
580 $q->where('post_title', 'like', '%' . $search_term . '%')
581 // Also search by product content/description
582 ->orWhere('post_content', 'like', '%' . $search_term . '%')
583 // Search by product excerpt
584 ->orWhere('post_excerpt', 'like', '%' . $search_term . '%');
585 });
586 }
587
588 $fluent_products = $query->get();
589
590 // Convert to the expected format
591 foreach ($fluent_products as $product) {
592 $products[$product->ID] = $product->post_title;
593 }
594
595 } catch (\Exception $e) {
596 // If FluentCart search fails, return empty array to trigger fallback
597 return [];
598 }
599
600 return $products;
601 }
602
603 /**
604 * Get products by category for enhanced search functionality
605 *
606 * @param string $category_slug The category slug to search for
607 * @return array Array of products in the specified category
608 */
609 public function get_products_by_category($category_slug = '') {
610 $products = [];
611
612 if (empty($category_slug)) {
613 return $products;
614 }
615
616 try {
617 // Get products that belong to the specified category
618 $args = array(
619 'post_type' => $this->post_type,
620 'post_status' => 'publish',
621 'posts_per_page' => 20,
622 'tax_query' => array(
623 array(
624 'taxonomy' => 'product-categories',
625 'field' => 'slug',
626 'terms' => $category_slug,
627 ),
628 ),
629 );
630
631 $query = new \WP_Query($args);
632
633 if ($query->have_posts()) {
634 while ($query->have_posts()) {
635 $query->the_post();
636 $products[get_the_ID()] = get_the_title();
637 }
638 wp_reset_postdata();
639 }
640
641 } catch (\Exception $e) {
642 // If category search fails, return empty array
643 return [];
644 }
645
646 return $products;
647 }
648
649 /**
650 * @todo remove in the future.
651 *
652 * @param [type] $data
653 * @param [type] $settings
654 * @return void
655 */
656 public function show_exclude_product( $data, $settings ){
657 $new_data = [];
658
659 if( ! empty( $data ) ) {
660 foreach( $data as $key => $product ) {
661 if( $this->_excludes_product($product, $settings) && $this->_show_purchaseof($product, $settings) ) {
662 $new_data[ $key ] = $product;
663 }
664 }
665 }
666
667 return $new_data;
668
669 }
670
671 /**
672 * Adds option to Link Type field in Content tab.
673 *
674 * @param array $options
675 * @return array
676 */
677 public function link_types($options) {
678 $options = GlobalFields::get_instance()->normalize_fields([
679 'product_page' => __('Product Page', 'notificationx'),
680 ], 'source', $this->id, $options);
681
682 return $options;
683 }
684
685 public function fallback_data($data, $entry) {
686 $data['name'] = __('Someone', 'notificationx');
687 $data['first_name'] = __('Someone', 'notificationx');
688 $data['last_name'] = __('Someone', 'notificationx');
689 $data['anonymous_title'] = __('Anonymous Product', 'notificationx');
690 if(empty($entry['product_title']) && !empty($entry['title'])){
691 $data['product_title'] = $entry['title'];
692 }
693 return $data;
694 }
695
696 public function source_error_message($messages) {
697 if (!$this->class_exists()) {
698 $url = admin_url('plugin-install.php?s=fluentcart&tab=search&type=term');
699 $messages[$this->id] = [
700 'message' => sprintf( '%s <a href="%s" target="_blank">%s</a> %s',
701 __( 'You have to install', 'notificationx' ),
702 $url,
703 __( 'FluentCart', 'notificationx' ),
704 __( 'plugin first.', 'notificationx' )
705 ),
706 'html' => true,
707 'type' => 'error',
708 'rules' => Rules::is('source', $this->id),
709 ];
710 }
711 return $messages;
712 }
713
714 public function doc(){
715 return sprintf(__('<p>Make sure that you have the <a target="_blank" href="%1$s">FluentCart WordPress plugin installed & configured</a> to use its campaign and selling data. For detailed guidelines, check out the step-by-step <a target="_blank" href="%2$s">documentation</a>.</p>
716 <a target="_blank" href="%3$s">👉 NotificationX Integration with FluentCart</a>', 'notificationx'),
717 'https://wordpress.org/plugins/fluent-cart/',
718 'https://notificationx.com/docs/fluentcart-sales-notifications/',
719 'https://notificationx.com/docs/fluentcart-sales-notifications/'
720 );
721 }
722
723 }
724
725