PluginProbe
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant / 2.2.7
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant v2.2.7
2.3.2 2.3.1 2.3.0 2.2.8 2.2.7 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.11.0 1.11.1 1.11.2 1.6 1.7 1.8 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 1.9.10 1.9.11 All 60 releases
merchant / inc / helpers.php

helpers.php in Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant 2.2.7, at inc/helpers.php

1,133 lines 32.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Helper functions.
5 *
6 * @package Merchant
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit; // Exit if accessed directly
11 }
12
13 /**
14 * Allowed tags general.
15 * Should be used to escape complex outputs like entire features html.
16 *
17 * @param array $extra
18 * @param bool $include_post_tags Whether to include post kses allowed tags or not. Default true.
19 *
20 * @return array $allowed_tags
21 */
22 if ( ! function_exists( 'merchant_kses_allowed_tags' ) ) {
23 function merchant_kses_allowed_tags( $extra = array(), $include_post_tags = true ) {
24 // Default
25 $allowed_tags = array_merge(
26 array(
27 // Meta
28 'meta' => array(
29 'name' => true,
30 'content' => true,
31 ),
32
33 // SVG Support
34 'svg' => array(
35 'class' => true,
36 'xmlns' => true,
37 'width' => true,
38 'height' => true,
39 'viewbox' => true,
40 'aria-hidden' => true,
41 'role' => true,
42 'focusable' => true,
43 'fill' => true,
44 'stroke' => true,
45 'stroke-linecap' => true,
46 'stroke-linejoin' => true,
47 'stroke-width' => true,
48 ),
49 'g' => array(
50 'id' => true,
51 'class' => true,
52 'clip-path' => true,
53 'style' => true,
54 'transform' => true,
55 ),
56 'path' => array(
57 'fill' => true,
58 'fill-rule' => true,
59 'd' => true,
60 'transform' => true,
61 'stroke' => true,
62 'stroke-width' => true,
63 'stroke-linejoin' => true,
64 'clip-rule' => true,
65 'opacity' => true,
66 ),
67 'polyline' => array(
68 'points' => true,
69 'fill' => true,
70 'fill-rule' => true,
71 'd' => true,
72 'transform' => true,
73 'stroke' => true,
74 'stroke-width' => true,
75 'stroke-linejoin' => true,
76 ),
77 'polygon' => array(
78 'fill' => true,
79 'fill-rule' => true,
80 'points' => true,
81 'transform' => true,
82 'focusable' => true,
83 'stroke' => true,
84 'stroke-width' => true,
85 ),
86 'rect' => array(
87 'x' => true,
88 'y' => true,
89 'rx' => true,
90 'width' => true,
91 'height' => true,
92 'transform' => true,
93 'fill' => true,
94 'stroke' => true,
95 'stroke-width' => true,
96 ),
97 'circle' => array(
98 'cx' => true,
99 'cy' => true,
100 'r' => true,
101 'width' => true,
102 'height' => true,
103 'transform' => true,
104 'fill' => true,
105 'stroke' => true,
106 'stroke-width' => true,
107 'stroke-linecap' => true,
108 'stroke-linejoin' => true,
109 ),
110 'line' => array(
111 'x1' => true,
112 'y1' => true,
113 'x2' => true,
114 'y2' => true,
115 'width' => true,
116 'height' => true,
117 'transform' => true,
118 'fill' => true,
119 'stroke' => true,
120 'stroke-width' => true,
121 'stroke-linecap' => true,
122 'stroke-linejoin' => true,
123 ),
124 'clipPath' => array(
125 'id' => true,
126 'class' => true,
127 'style' => true,
128 ),
129 'defs' => array(
130 'id' => true,
131 ),
132 'progress' => array(
133 'id' => true,
134 'class' => true,
135 'value' => true,
136 'max' => true,
137 ),
138 ),
139 $include_post_tags ? wp_kses_allowed_html( 'post' ) : array()
140 );
141
142 // Include schema markup tags
143 if ( in_array( 'schema_markup', $extra, true ) || in_array( 'all', $extra, true ) ) {
144 $tags = array( 'meta', 'nav', 'ul', 'li', 'a', 'span' );
145
146 foreach ( $tags as $tag ) {
147 if ( isset( $allowed_tags[ $tag ] ) ) {
148 $allowed_tags[ $tag ]['itemprop'] = true;
149 $allowed_tags[ $tag ]['itemscope'] = true;
150 $allowed_tags[ $tag ]['itemtype'] = true;
151 } else {
152 $allowed_tags[ $tag ] = array(
153 'itemprop' => true,
154 'itemscope' => true,
155 'itemtype' => true,
156 );
157 }
158 }
159 }
160
161 // Include iframe tags
162 if ( in_array( 'iframe', $extra, true ) || in_array( 'all', $extra, true ) ) {
163 $allowed_tags['iframe'] = array(
164 'src' => true,
165 'height' => true,
166 'width' => true,
167 'frameborder' => true,
168 'allowfullscreen' => true,
169 );
170 }
171
172 if ( in_array( 'wc_email', $extra, true ) || in_array( 'all', $extra, true ) ) {
173 $allowed_tags['body'] = array(
174 'class' => true,
175 'style' => true,
176 'leftmargin' => true,
177 'marginwidth' => true,
178 'topmargin' => true,
179 'marginheight' => true,
180 'offset' => true,
181 );
182
183 $allowed_tags['html'] = array(
184 'lang' => true,
185 );
186
187 $allowed_tags['style'] = array(
188 'type' => true,
189 );
190 $allowed_tags['head'] = array();
191 $allowed_tags['meta']['http-equiv'] = true;
192 }
193
194 // Include nonce tags
195 if ( in_array( 'nonce', $extra, true ) || in_array( 'all', $extra, true ) ) {
196 $allowed_tags['input'] = array(
197 'type' => true,
198 'id' => true,
199 'name' => true,
200 'value' => true,
201 'data-name' => true,
202 );
203 }
204
205 // Include bdi tag
206 if ( in_array( 'bdi', $extra, true ) || in_array( 'all', $extra, true ) ) {
207 $allowed_tags['bdi'] = array(
208 'class' => true,
209 'id' => true,
210 'style' => true,
211 );
212 }
213
214 // Include select2
215 if ( in_array( 'select2', $extra, true ) || in_array( 'all', $extra, true ) ) {
216 $allowed_tags['select'] = array(
217 'name' => true,
218 'class' => true,
219 'id' => true,
220 'style' => true,
221 'data-name' => true,
222 'data-source' => true,
223 'multiple' => true,
224 );
225
226 $allowed_tags['option'] = array(
227 'value' => true,
228 'selected' => true,
229 );
230
231 $allowed_tags['optgroup'] = array(
232 'label' => true,
233 );
234 }
235
236 // Include dd, dt tags
237 if ( in_array( 'dd', $extra, true ) || in_array( 'all', $extra, true ) ) {
238 $allowed_tags['dd'] = array(
239 'class' => true,
240 'id' => true,
241 'style' => true,
242 );
243
244 $allowed_tags['dt'] = array(
245 'class' => true,
246 'id' => true,
247 'style' => true,
248 );
249 }
250
251 // Include forms tags.
252 if ( in_array( 'forms', $extra, true ) || in_array( 'all', $extra, true ) ) {
253 $tags = array( 'form', 'input', 'select', 'option', 'textarea', 'a' );
254
255 foreach ( $tags as $tag ) {
256 $allowed_tags[ $tag ] = array(
257 'id' => true,
258 'class' => true,
259 'style' => true,
260 'name' => true,
261 'href' => true,
262 'target' => true,
263 'value' => true,
264 'type' => true,
265 'placeholder' => true,
266 'data' => '*',
267 'data-source' => true,
268 'data-product_id' => true,
269 'data-product_variations' => true,
270 'data-attribute_name' => true,
271 'data-show_option_none' => true,
272 'data-name' => true,
273 'data-allowed-types' => true,
274 'step' => true,
275 'min' => true,
276 'max' => true,
277 'selected' => true,
278 'checked' => true,
279 'onchange' => true,
280 'autocomplete' => true,
281 'required' => true,
282 'action' => true,
283 'method' => true,
284 'enctype' => true,
285 'size' => true,
286 'role' => true,
287 'inputmode' => true,
288 'aria-label' => true,
289 'multiple' => true,
290 );
291
292 if ( $tag === 'a' ) {
293 $allowed_tags[ $tag ]['href'] = true;
294 $allowed_tags[ $tag ]['title'] = true;
295 $allowed_tags[ $tag ]['target'] = true;
296 }
297 }
298 }
299
300
301 // Include script tag
302 if ( in_array( 'script', $extra, true ) ) {
303 $allowed_tags['script'] = array(
304 'id' => true,
305 'src' => true,
306 'type' => true,
307 'async' => true,
308 'defer' => true,
309 );
310 }
311
312 if ( in_array( 'div', $extra, true ) ) {
313 $tags = array( 'form', 'input', 'select', 'option', 'textarea', 'a', 'div' );
314
315 foreach ( $tags as $tag ) {
316 $allowed_tags[ $tag ] = array(
317 'id' => true,
318 'class' => true,
319 'style' => true,
320 'name' => true,
321 'href' => true,
322 'target' => true,
323 'value' => true,
324 'type' => true,
325 'placeholder' => true,
326 'data' => '*',
327 'data-source' => true,
328 'data-product_id' => true,
329 'data-product_variations' => true,
330 'data-attribute_name' => true,
331 'data-show_option_none' => true,
332 'data-name' => true,
333 'data-allowed-types' => true,
334 'step' => true,
335 'min' => true,
336 'max' => true,
337 'selected' => true,
338 'checked' => true,
339 'onchange' => true,
340 'autocomplete' => true,
341 'required' => true,
342 'action' => true,
343 'method' => true,
344 'enctype' => true,
345 'size' => true,
346 'role' => true,
347 'inputmode' => true,
348 'aria-label' => true,
349 'multiple' => true,
350 'title' => true,
351 'data-id' => true,
352 'data-product-id' => true,
353 );
354
355 if ( $tag === 'a' ) {
356 $allowed_tags[ $tag ]['href'] = true;
357 $allowed_tags[ $tag ]['title'] = true;
358 $allowed_tags[ $tag ]['target'] = true;
359 }
360 }
361 }
362
363 /**
364 * Filters the allowed tags.
365 *
366 * @since 1.2.5
367 */
368 return apply_filters( 'merchant_kses_allowed_tags', $allowed_tags );
369 }
370 }
371
372 /**
373 * Allowed tags for scripts.
374 *
375 * @return array $allowed_tags
376 */
377 if ( ! function_exists( 'merchant_kses_allowed_tags_for_code_snippets' ) ) {
378 function merchant_kses_allowed_tags_for_code_snippets() {
379 return array(
380 'script' => array(
381 'type' => true,
382 ),
383 );
384 }
385 }
386
387 /**
388 * Format a price for admin preview display.
389 *
390 * Uses wc_price() when WooCommerce is available, otherwise falls back to a plain
391 * currency symbol + number_format string.
392 *
393 * @param float $price The price value.
394 * @param string $currency Currency symbol fallback (used only when WC is unavailable).
395 *
396 * @return string Formatted price HTML.
397 *
398 * @since 2.2.5
399 */
400 if ( ! function_exists( 'merchant_preview_price' ) ) {
401 function merchant_preview_price( $price, $currency = '$' ) {
402 if ( function_exists( 'wc_price' ) ) {
403 return wp_kses( wc_price( $price ), merchant_kses_allowed_tags( array( 'bdi' ) ) );
404 }
405
406 return esc_html( $currency ) . esc_html( number_format( (float) $price, 2 ) );
407 }
408 }
409
410 /**
411 * Check if WooCommerce checkout page is being rendered by block.
412 * Since WooCommerce 8.3.0 the checkout page is rendered by block.
413 *
414 * @return bool
415 */
416 if ( ! function_exists( 'merchant_is_checkout_block_layout' ) ) {
417 function merchant_is_checkout_block_layout() {
418 $checkout_page = wc_get_page_id( 'checkout' );
419
420 if ( empty( $checkout_page ) ) {
421 return false;
422 }
423
424 if ( function_exists( 'has_blocks' ) && has_blocks( $checkout_page ) ) {
425 $post = get_post( $checkout_page );
426 $blocks = parse_blocks( $post->post_content );
427
428 foreach ( $blocks as $block ) {
429 if ( 'woocommerce/checkout' === $block['blockName'] ) {
430 return true;
431 }
432 }
433 }
434
435 return false;
436 }
437 }
438
439 /**
440 * Check if WooCommerce cart page is being rendered by block.
441 * Since WooCommerce 8.3.0 the cart page is rendered by block.
442 *
443 * @return bool
444 */
445 if ( ! function_exists( 'merchant_is_cart_block_layout' ) ) {
446 function merchant_is_cart_block_layout() {
447 $cart_page = wc_get_page_id( 'cart' );
448
449 if ( empty( $cart_page ) ) {
450 return false;
451 }
452
453 if ( function_exists( 'has_blocks' ) && has_blocks( $cart_page ) ) {
454 $post = get_post( $cart_page );
455 $blocks = parse_blocks( $post->post_content );
456
457 foreach ( $blocks as $block ) {
458 if ( 'woocommerce/cart' === $block['blockName'] ) {
459 return true;
460 }
461 }
462 }
463
464 return false;
465 }
466 }
467
468 /**
469 * Get the product categories.
470 */
471 if ( ! function_exists( 'merchant_get_product_categories' ) ) {
472 function merchant_get_product_categories() {
473 $args = array(
474 'taxonomy' => 'product_cat',
475 'hide_empty' => false,
476 );
477
478 $categories = get_terms( $args );
479
480 $categories_tree = array();
481 $indexed_categories = array();
482
483 if ( ! empty( $categories ) && ! is_wp_error( $categories ) ) {
484 foreach ( $categories as $category ) {
485 $indexed_categories[ $category->term_id ] = array(
486 'id' => $category->term_id,
487 'slug' => $category->slug,
488 'name' => $category->name,
489 'parent' => $category->parent,
490 'children' => array(),
491 );
492 }
493
494 foreach ( $indexed_categories as &$cat ) {
495 if ( (int) $cat['parent'] === 0 ) {
496 $categories_tree[] = &$cat;
497 } else {
498 $indexed_categories[ $cat['parent'] ]['children'][] = &$cat;
499 }
500 }
501 }
502
503 return $categories_tree;
504 }
505 }
506
507 /**
508 * Get the product tags.
509 */
510 if ( ! function_exists( 'merchant_get_product_tags' ) ) {
511 function merchant_get_product_tags() {
512 $product_tags = get_terms( array(
513 'taxonomy' => 'product_tag',
514 'hide_empty' => false,
515 ) );
516
517 $tag_names = array();
518
519 if ( ! empty( $product_tags ) && ! is_wp_error( $product_tags ) ) {
520 foreach ( $product_tags as $tag ) {
521 $tag_names[ $tag->slug ] = $tag->name;
522 }
523 }
524
525 return $tag_names;
526 }
527 }
528
529 /**
530 * Convert array to css.
531 */
532 if ( ! function_exists( 'merchant_array_to_css' ) ) {
533 function merchant_array_to_css( $css_array ) {
534 $css = '';
535 if ( empty( $css_array ) ) {
536 return $css;
537 }
538 foreach ( $css_array as $key => $value ) {
539 $css .= $key . ':' . $value . ';';
540 }
541
542 return $css;
543 }
544 }
545
546 /**
547 * Get the share link data structure.
548 *
549 * @return array
550 */
551 if ( ! function_exists( 'merchant_get_share_link_data' ) ) {
552 function merchant_get_share_link_data() {
553 return array(
554 'facebook' => array(
555 'url' => 'https://www.facebook.com/sharer.php?u={{url}}',
556 'title' => __( 'Facebook', 'merchant' ),
557 ),
558 'twitter' => array(
559 'url' => 'https://twitter.com/intent/tweet?url={{url}}&text={{title}}',
560 'title' => __( 'X', 'merchant' ),
561 ),
562 'linkedin' => array(
563 'url' => 'https://www.linkedin.com/sharing/share-offsite/?url={{url}}',
564 'title' => __( 'LinkedIn', 'merchant' ),
565 ),
566 'reddit' => array(
567 'url' => 'https://reddit.com/submit?url={{url}}&title={{title}}',
568 'title' => __( 'Reddit', 'merchant' ),
569 ),
570 'whatsapp' => array(
571 'url' => 'https://api.whatsapp.com/send/?text={{url}}',
572 'title' => __( 'WhatsApp', 'merchant' ),
573 ),
574 'pinterest' => array(
575 'url' => 'http://pinterest.com/pin/create/link/?url={{url}}',
576 'title' => __( 'Pinterest', 'merchant' ),
577 ),
578 'telegram' => array(
579 'url' => 'https://t.me/share/url?url={{url}}&text={{title}}',
580 'title' => __( 'Telegram', 'merchant' ),
581 ),
582 'weibo' => array(
583 'url' => 'http://service.weibo.com/share/share.php?url={{url}}&appkey=&title={{title}}&pic=&ralateUid=',
584 'title' => __( 'Weibo', 'merchant' ),
585 ),
586 'vk' => array(
587 'url' => 'http://vk.com/share.php?url={{url}}&title={{title}}&comment={text}',
588 'title' => __( 'VK', 'merchant' ),
589 ),
590 'ok' => array(
591 'url' => 'https://connect.ok.ru/dk?st.cmd=WidgetSharePreview&st.shareUrl={{url}}',
592 'title' => __( 'OK', 'merchant' ),
593 ),
594 'xing' => array(
595 'url' => 'https://www.xing.com/spi/shares/new?url={{url}}',
596 'title' => __( 'Xing', 'merchant' ),
597 ),
598 'mail' => array(
599 'url' => 'mailto:?subject={{title}}&body={{url}}',
600 'title' => __( 'Mail', 'merchant' ),
601 ),
602 );
603 }
604 }
605
606 /**
607 * Get the share link url.
608 *
609 * @param string $social_network
610 *
611 * @return string
612 */
613 if ( ! function_exists( 'merchant_get_share_link_url' ) ) {
614 function merchant_get_share_link_url( $social_network, $url_to_share, $title_to_share = '' ) {
615 $share_link_data = merchant_get_share_link_data();
616
617 if ( ! isset( $share_link_data[ $social_network ] ) ) {
618 return '';
619 }
620
621 $share_link_url = str_replace(
622 array( '{{url}}', '{{title}}' ),
623 array( $url_to_share, $title_to_share ),
624 $share_link_data[ $social_network ]['url']
625 );
626
627 return $share_link_url;
628 }
629 }
630
631 /**
632 * Get the share link title.
633 *
634 * @param string $social_network
635 *
636 * @return string
637 */
638 if ( ! function_exists( 'merchant_get_share_link_title' ) ) {
639 function merchant_get_share_link_title( $social_network ) {
640 $share_link_data = merchant_get_share_link_data();
641
642 return isset( $share_link_data[ $social_network ] ) ? $share_link_data[ $social_network ]['title'] : '';
643 }
644 }
645
646 if ( ! function_exists( 'merchant_timezone' ) ) {
647 /**
648 * Get the WP timezone.
649 *
650 * @return string
651 */
652 function merchant_timezone() {
653 /**
654 * Filter the storewide sale timezone.
655 *
656 * @param string $timezone
657 *
658 * @since 1.9.9
659 */
660 return apply_filters(
661 'merchant_storewide_sale_timezone',
662 wp_timezone_string()
663 );
664 }
665 }
666
667 if ( ! function_exists( 'merchant_get_current_timestamp' ) ) {
668 /**
669 * Get the current timestamp.
670 *
671 * @return int|string
672 */
673 function merchant_get_current_timestamp() {
674 $timezone = new DateTimeZone( merchant_timezone() );
675
676 // Get the timestamp
677 return ( new DateTime( 'now', $timezone ) )->getTimestamp();
678 }
679 }
680
681 if ( ! function_exists( 'merchant_convert_date_to_timestamp' ) ) {
682 /**
683 * Convert date to timestamp.
684 *
685 * @param string $date The date to convert
686 * @param string $format The format of the date
687 *
688 * @return int The timestamp
689 */
690 function merchant_convert_date_to_timestamp( $date, $format = 'm-d-Y h:i A' ) {
691 $timezone = new DateTimeZone( merchant_timezone() );
692 $date_object = DateTime::createFromFormat( $format, $date, $timezone ); // Create DateTime object with specified format and timezone
693 if ( false === $date_object ) {
694 return 0;
695 }
696
697 return $date_object->getTimestamp(); // Output the timestamp
698 }
699 }
700
701 if ( ! function_exists( 'merchant_date_string_to_timestamp' ) ) {
702 /**
703 * Convert a date string to a Unix timestamp based on the specified format and timezone.
704 *
705 * This function signature matches Merchant Pro for compatibility.
706 *
707 * @param string $date The date string to convert.
708 * @param string|null $timezone_offset The timezone offset or timezone string. Defaults to WordPress timezone.
709 * @param string $format The format of the date string. Defaults to 'm-d-Y h:i A'.
710 *
711 * @return int The timestamp, or 0 on failure.
712 */
713 function merchant_date_string_to_timestamp( $date, $timezone_offset = null, $format = 'm-d-Y h:i A' ) {
714 try {
715 // If it's already numeric, return it as-is
716 if ( is_numeric( $date ) ) {
717 return (int) $date;
718 }
719
720 // Use WordPress timezone if not specified
721 $timezone_offset = $timezone_offset ?? wp_timezone_string();
722
723 // Create DateTime object from the specified format and timezone
724 $date_object = DateTime::createFromFormat( $format, $date, new DateTimeZone( $timezone_offset ) );
725
726 return $date_object ? $date_object->getTimestamp() : 0;
727 } catch ( Exception $e ) {
728 return 0;
729 }
730 }
731 }
732
733 /**
734 * Parses a list of product IDs
735 * @return array
736 */
737 if ( ! function_exists( 'merchant_parse_product_ids' ) ) {
738 function merchant_parse_product_ids( $product_ids ) {
739 $parsed_ids = $product_ids ?? array();
740
741 // Convert to array if it's not already an array
742 $parsed_ids = ! is_array( $parsed_ids ) ? explode( ',', $parsed_ids ) : $parsed_ids;
743
744 // Convert all elements to integers
745 $parsed_ids = array_map( 'intval', $parsed_ids );
746
747 return $parsed_ids;
748 }
749 }
750
751 /**
752 * Check if the user condition is passed.
753 *
754 * @param $args
755 *
756 * @return bool
757 */
758 if ( ! function_exists( 'merchant_is_user_condition_passed' ) ) {
759 function merchant_is_user_condition_passed( $args = array() ) {
760 $args = is_array( $args ) ? $args : array();
761
762 $is_logged_in = is_user_logged_in();
763 $current_user = $is_logged_in ? wp_get_current_user() : null;
764 $customer_id = is_object( $current_user ) && isset( $current_user->ID ) ? (int) $current_user->ID : 0;
765 $user_role = is_object( $current_user ) && isset( $current_user->roles ) && ! empty( $current_user->roles ) ? $current_user->roles[0] : '';
766
767 $condition = $args['user_condition'] ?? 'all';
768
769 $is_exclusion_enabled = $args['user_exclusion_enabled'] ?? false;
770 $excluded_customers = array_map( 'intval', $args['exclude_users'] ?? array() );
771 $excluded_roles = $args['exclude_roles'] ?? array();
772
773 switch ( $condition ) {
774 case 'all':
775 case '':
776 if ( $is_exclusion_enabled ) {
777 if ( in_array( $customer_id, $excluded_customers, true ) ) {
778 return false;
779 }
780
781 if ( $condition === 'all' && in_array( $user_role, $excluded_roles, true ) ) {
782 return false;
783 }
784 }
785
786 return true;
787
788 case 'logged-in':
789 return $is_logged_in;
790
791 case 'roles':
792 if ( $is_exclusion_enabled && in_array( $customer_id, $excluded_customers, true ) ) {
793 return false;
794 }
795
796 $allowed_roles = $args['user_condition_roles'] ?? array();
797 return in_array( $user_role, $allowed_roles, true );
798
799 case 'customers':
800 case 'users':
801 $allowed_customers = array_map( 'intval', $args['user_condition_users'] ?? array() );
802 return $is_logged_in && in_array( $customer_id, $allowed_customers, true );
803
804 default:
805 return false;
806 }
807 }
808 }
809
810 /**
811 * Check if a product is excluded based on given arguments.
812 *
813 * @param $product_id
814 * @param $args
815 *
816 * @return bool
817 */
818 if ( ! function_exists( 'merchant_is_product_excluded' ) ) {
819 function merchant_is_product_excluded( $product_id, $args = array() ) {
820 if ( empty( $args['exclusion_enabled'] ) ) {
821 return false;
822 }
823
824 $display_rule = $args['rules_to_display'] ?? $args['display_rules'] ?? $args['rules_to_apply'] ?? $args['trigger_on'] ?? 'products';
825
826 $rules = array(
827 'all',
828 'all_products',
829 'categories',
830 'category',
831 'by_category',
832 'tags',
833 'by_tags',
834 'featured_products',
835 'products_on_sale',
836 'new_products',
837 'out_of_stock',
838 'pre-order',
839 );
840
841 $product = wc_get_product( $product_id );
842 $_product_id = $product && $product->is_type( 'variation' ) ? $product->get_parent_id() : $product_id;
843
844 // Exclude products
845 if ( in_array( $display_rule, $rules, true ) ) {
846 $excluded_product_ids = $args['excluded_products'] ?? array();
847 $excluded_product_ids = merchant_parse_product_ids( $excluded_product_ids );
848
849 if ( in_array( (int) $product_id, $excluded_product_ids, true ) || in_array( (int) $_product_id, $excluded_product_ids, true ) ) {
850 return true;
851 }
852 }
853
854 // Exclude categories
855 if ( in_array( $display_rule, array( 'all', 'all_products', 'categories', 'category', 'by_category' ), true ) ) {
856 $excluded_categories_slugs = $args['excluded_categories'] ?? array();
857
858 if ( ! empty( $excluded_categories_slugs ) && has_term( $excluded_categories_slugs, 'product_cat', $_product_id ) ) {
859 return true;
860 }
861 }
862
863 // Exclude tags
864 if ( in_array( $display_rule, array( 'all', 'all_products', 'tags', 'by_tags' ), true ) ) {
865 $excluded_tags_slugs = $args['excluded_tags'] ?? array();
866
867 if ( ! empty( $excluded_tags_slugs ) && has_term( $excluded_tags_slugs, 'product_tag', $_product_id ) ) {
868 return true;
869 }
870 }
871
872 // Exclude brands
873 if ( in_array( $display_rule, array( 'all', 'all_products', 'brands', 'by_brands' ), true ) ) {
874 $excluded_brands_slugs = $args['excluded_brands'] ?? array();
875
876 if ( ! empty( $excluded_brands_slugs ) && has_term( $excluded_brands_slugs, 'product_brand', $_product_id ) ) {
877 return true;
878 }
879 }
880
881 // Exclude categories with toggle
882 if ( ! empty( $args['exclude_categories_toggle'] ) && in_array( $display_rule, array( 'all', 'all_products', 'categories', 'category', 'by_category' ), true ) ) {
883 $excluded_categories_slugs = $args['excluded_categories'] ?? array();
884
885 if ( ! empty( $excluded_categories_slugs ) && has_term( $excluded_categories_slugs, 'product_cat', $_product_id ) ) {
886 return true;
887 }
888 }
889
890 // Exclude tags with toggle
891 if ( ! empty( $args['exclude_tags_toggle'] ) && in_array( $display_rule, array( 'all', 'all_products', 'tags', 'by_tags' ), true ) ) {
892 $excluded_tags_slugs = $args['excluded_tags'] ?? array();
893
894 if ( ! empty( $excluded_tags_slugs ) && has_term( $excluded_tags_slugs, 'product_tag', $_product_id ) ) {
895 return true;
896 }
897 }
898
899 // Exclude brands with toggle
900 if ( ! empty( $args['exclude_brands_toggle'] ) && in_array( $display_rule, array( 'all', 'all_products', 'brands', 'by_brands' ), true ) ) {
901 $excluded_brands_slugs = $args['excluded_brands'] ?? array();
902
903 if ( ! empty( $excluded_brands_slugs ) && has_term( $excluded_brands_slugs, 'product_brand', $_product_id ) ) {
904 return true;
905 }
906 }
907
908 return false;
909 }
910 }
911
912 /**
913 * Check if a product or any of its variations is excluded based on the given offer.
914 *
915 * This method determines if a product (simple or variable) or any of its variations
916 * satisfies the merchant exclusion rules.
917 *
918 * @param int $product_id The ID of the product to check.
919 * @param array $offer The offer data to evaluate against exclusion rules.
920 *
921 * @return bool True if the product or any of its variations is excluded, false otherwise.
922 */
923 if ( ! function_exists( 'merchant_is_product_or_variation_excluded' ) ) {
924 function merchant_is_product_or_variation_excluded( $product_id, $offer = array() ) {
925 $product = wc_get_product( $product_id );
926
927 if ( ! $product ) {
928 return false;
929 }
930
931 // Get IDs to check for exclusion
932 $product_ids = $product->is_type( 'variable' ) ? $product->get_children() : array( $product_id );
933
934 foreach ( $product_ids as $id ) {
935 if ( merchant_is_product_excluded( $id, $offer ) ) {
936 return true; // Excluded if any ID matches
937 }
938 }
939
940 return false;
941 }
942 }
943
944 /**
945 * Get the label of the first active payment gateway in WooCommerce.
946 *
947 * @return string|null The label of the first active payment gateway, or null if none are found.
948 */
949 if ( ! function_exists( 'merchant_get_first_active_payment_gateway_label' ) ) {
950 function merchant_get_first_active_payment_gateway_label() {
951 // Get the available payment gateways
952 $available_gateways = WC()->payment_gateways->get_available_payment_gateways();
953
954 // Check if there are any active gateways
955 if ( ! empty( $available_gateways ) ) {
956 // Get the first active gateway
957 return reset( $available_gateways )->get_title();
958 }
959
960 // Return null if no active gateways are found
961 return null;
962 }
963 }
964
965 /**
966 * Get the review count of a product.
967 *
968 * @param int $product_id The ID of the product to get the review count for.
969 *
970 * @return int The review count of the product.
971 */
972 if ( ! function_exists( 'merchant_get_product_reviews_count' ) ) {
973 function merchant_get_product_reviews_count( $product_id ) {
974 $product = wc_get_product( $product_id );
975
976 return $product ? $product->get_review_count() : 0;
977 }
978 }
979
980 if ( ! function_exists( 'merchant_get_modules_campaign_data' ) ) {
981 /**
982 * Retrieves campaign data for a specific module.
983 *
984 * This function fetches campaign data based on the provided module ID and processes it
985 * into a standardized format. The campaigns are indexed by their `flexible_id` (expected to be a UUID v4)
986 * and include details such as ID, title, and status.
987 *
988 * @param string $module_id The ID of the module for which to retrieve campaign data.
989 * Expected values include constants like `Merchant_Buy_X_Get_Y::MODULE_ID`,
990 * `Merchant_Pre_Orders::MODULE_ID`, and `Merchant_Product_Labels::MODULE_ID`.
991 *
992 * @return array An associative array of campaigns, where each key is the `flexible_id` (UUID v4)
993 * of the campaign, and the value is an array containing the campaign's `id`, `title`,
994 * and `status`.
995 * Example:
996 * [
997 * '550e8400-e29b-41d4-a716-446655440000' => [
998 * 'id' => '550e8400-e29b-41d4-a716-446655440000',
999 * 'title' => 'Campaign Title',
1000 * 'status' => 'active',
1001 * ],
1002 * 'f47ac10b-58cc-4372-a567-0e02b2c3d479' => [
1003 * 'id' => 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
1004 * 'title' => 'Another Campaign',
1005 * 'status' => 'inactive',
1006 * ],
1007 * ]
1008 */
1009 function merchant_get_module_campaigns_data( $module_id ) {
1010 $campaigns = array();
1011
1012 // Determine the key to use based on the module ID
1013 $key = '';
1014 if ( Merchant_Buy_X_Get_Y::MODULE_ID === $module_id || Merchant_Pre_Orders::MODULE_ID === $module_id ) {
1015 $key = 'rules';
1016 } elseif ( Merchant_Product_Labels::MODULE_ID === $module_id ) {
1017 $key = 'labels';
1018 } else {
1019 $key = 'offers';
1020 }
1021
1022 // Fetch the module campaigns
1023 $module_campaigns = Merchant_Admin_Options::get( $module_id, $key, array() );
1024 if ( empty( $module_campaigns ) ) {
1025 return $campaigns;
1026 }
1027
1028 // Process each campaign
1029 foreach ( $module_campaigns as $campaign ) {
1030 if ( empty( $campaign['flexible_id'] ) ) {
1031 continue;
1032 }
1033
1034 $campaigns[ $campaign['flexible_id'] ] = array(
1035 'campaign_key' => $key,
1036 'campaign_id' => $campaign['flexible_id'],
1037 'campaign_title' => $campaign['offer-title'] ?? $campaign['label-title'] ?? '',
1038 'campaign_status' => ( isset( $campaign['campaign_status'] ) && $campaign['campaign_status'] === 'inactive' ) ? 'inactive' : 'active',
1039 );
1040 }
1041
1042 return $campaigns;
1043 }
1044 }
1045
1046 if ( ! function_exists( 'merchant_get_modules_data' ) ) {
1047 /**
1048 * Get the data of all the modules.
1049 *
1050 * @return array
1051 */
1052 function merchant_get_modules_data() {
1053 $modules = array();
1054 $registered_modules = Merchant_Admin_Modules::get_modules();
1055 foreach ( $registered_modules as $module_category => $module_data ) {
1056 foreach ( $module_data['modules'] as $module_id => $module ) {
1057 if ( ! empty( $module ) ) {
1058 $modules[ $module_id ] = array(
1059 'id' => $module_id,
1060 'active' => Merchant_Modules::is_module_active( $module_id ),
1061 'name' => $module['title'],
1062 'desc' => $module['desc'],
1063 'category' => $module_category,
1064 'pro' => $module['pro'],
1065 );
1066
1067 $campaigns = merchant_get_module_campaigns_data( $module_id );
1068
1069 if ( ! empty( $campaigns ) ) {
1070 $modules[ $module_id ]['campaigns'] = $campaigns;
1071 }
1072 }
1073 }
1074 }
1075
1076 return $modules;
1077 }
1078 }
1079
1080 if ( ! function_exists( 'merchant_get_active_modules' ) ) {
1081 /**
1082 * Get the active modules.
1083 *
1084 * @return array
1085 */
1086 function merchant_get_active_modules() {
1087 $modules = array_keys( merchant_get_modules_data() );
1088
1089 return array_values( array_filter( $modules, static function ( $module_id ) {
1090 return Merchant_Modules::is_module_active( $module_id );
1091 } ) );
1092 }
1093 }
1094
1095 if ( ! function_exists( 'merchant_get_campaign_data' ) ) {
1096 /**
1097 * Get the data of a specific campaign.
1098 *
1099 * @param string $campaign_id The ID of the campaign.
1100 * @param string $module_id The ID of the module.
1101 *
1102 * @return array
1103 */
1104 function merchant_get_campaign_data( $campaign_id, $module_id ) {
1105 if ( Merchant_Buy_X_Get_Y::MODULE_ID === $module_id || Merchant_Pre_Orders::MODULE_ID === $module_id ) {
1106 $key = 'rules';
1107 } elseif ( Merchant_Product_Labels::MODULE_ID === $module_id ) {
1108 $key = 'labels';
1109 } else {
1110 $key = 'offers';
1111 }
1112
1113 $all_modules = merchant_get_modules_data();
1114 $module_campaigns = Merchant_Admin_Options::get( $module_id, $key, array() );
1115 if ( ! empty( $module_campaigns ) ) {
1116 foreach ( $module_campaigns as $campaign ) {
1117 if ( isset( $all_modules[ $module_id ], $campaign['flexible_id'] ) && $campaign_id === $campaign['flexible_id'] ) {
1118 return array(
1119 'campaign_id' => $campaign['flexible_id'],
1120 'campaign_title' => $campaign['offer-title'] ?? $campaign['label-title'] ?? '',
1121 'campaign_status' => $campaign['status'] ?? 'active',
1122 'module_id' => $module_id,
1123 'module_name' => $all_modules[ $module_id ]['name'],
1124 'is_pro' => $all_modules[ $module_id ]['pro'],
1125 'is_module_active' => $all_modules[ $module_id ]['active'],
1126 );
1127 }
1128 }
1129 }
1130
1131 return array();
1132 }
1133 }