PluginProbe
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant / 1.11.0
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant v1.11.0
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 1.11.0, at inc/helpers.php

879 lines 22.8 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 ),
66 'polyline' => array(
67 'points' => true,
68 'fill' => true,
69 'fill-rule' => true,
70 'd' => true,
71 'transform' => true,
72 'stroke' => true,
73 'stroke-width' => true,
74 'stroke-linejoin' => true,
75 ),
76 'polygon' => array(
77 'fill' => true,
78 'fill-rule' => true,
79 'points' => true,
80 'transform' => true,
81 'focusable' => true,
82 'stroke' => true,
83 'stroke-width' => true,
84 ),
85 'rect' => array(
86 'x' => true,
87 'y' => true,
88 'rx' => true,
89 'width' => true,
90 'height' => true,
91 'transform' => true,
92 'fill' => true,
93 'stroke' => true,
94 'stroke-width' => true,
95 ),
96 'circle' => array(
97 'cx' => true,
98 'cy' => true,
99 'r' => true,
100 'width' => true,
101 'height' => true,
102 'transform' => true,
103 'fill' => true,
104 'stroke' => true,
105 'stroke-width' => true,
106 'stroke-linecap' => true,
107 'stroke-linejoin' => true,
108 ),
109 'line' => array(
110 'x1' => true,
111 'y1' => true,
112 'x2' => true,
113 'y2' => true,
114 'width' => true,
115 'height' => true,
116 'transform' => true,
117 'fill' => true,
118 'stroke' => true,
119 'stroke-width' => true,
120 'stroke-linecap' => true,
121 'stroke-linejoin' => true,
122 ),
123 'clipPath' => array(
124 'id' => true,
125 'class' => true,
126 'style' => true,
127 ),
128 'defs' => array(
129 'id' => true,
130 ),
131 'progress' => array(
132 'id' => true,
133 'class' => true,
134 'value' => true,
135 'max' => true,
136 ),
137 ),
138 $include_post_tags ? wp_kses_allowed_html( 'post' ) : array()
139 );
140
141 // Include schema markup tags
142 if ( in_array( 'schema_markup', $extra, true ) || in_array( 'all', $extra, true ) ) {
143 $tags = array( 'meta', 'nav', 'ul', 'li', 'a', 'span' );
144
145 foreach ( $tags as $tag ) {
146 if ( isset( $allowed_tags[ $tag ] ) ) {
147 $allowed_tags[ $tag ]['itemprop'] = true;
148 $allowed_tags[ $tag ]['itemscope'] = true;
149 $allowed_tags[ $tag ]['itemtype'] = true;
150 } else {
151 $allowed_tags[ $tag ] = array(
152 'itemprop' => true,
153 'itemscope' => true,
154 'itemtype' => true,
155 );
156 }
157 }
158 }
159
160 // Include iframe tags
161 if ( in_array( 'iframe', $extra, true ) || in_array( 'all', $extra, true ) ) {
162 $allowed_tags['iframe'] = array(
163 'src' => true,
164 'height' => true,
165 'width' => true,
166 'frameborder' => true,
167 'allowfullscreen' => true,
168 );
169 }
170
171 if ( in_array( 'wc_email', $extra, true ) || in_array( 'all', $extra, true ) ) {
172 $allowed_tags['body'] = array(
173 'class' => true,
174 'style' => true,
175 'leftmargin' => true,
176 'marginwidth' => true,
177 'topmargin' => true,
178 'marginheight' => true,
179 'offset' => true,
180 );
181
182 $allowed_tags['html'] = array(
183 'lang' => true,
184 );
185
186 $allowed_tags['style'] = array(
187 'type' => true,
188 );
189 $allowed_tags['head'] = array();
190 $allowed_tags['meta']['http-equiv'] = true;
191 }
192
193 // Include nonce tags
194 if ( in_array( 'nonce', $extra, true ) || in_array( 'all', $extra, true ) ) {
195 $allowed_tags['input'] = array(
196 'type' => true,
197 'id' => true,
198 'name' => true,
199 'value' => true,
200 'data-name' => true,
201 );
202 }
203
204 // Include bdi tag
205 if ( in_array( 'bdi', $extra, true ) || in_array( 'all', $extra, true ) ) {
206 $allowed_tags['bdi'] = array(
207 'class' => true,
208 'id' => true,
209 'style' => true,
210 );
211 }
212
213 // Include select2
214 if ( in_array( 'select2', $extra, true ) || in_array( 'all', $extra, true ) ) {
215 $allowed_tags['select'] = array(
216 'name' => true,
217 'class' => true,
218 'id' => true,
219 'style' => true,
220 'data-name' => true,
221 'data-source' => true,
222 'multiple' => true,
223 );
224
225 $allowed_tags['option'] = array(
226 'value' => true,
227 'selected' => true,
228 );
229
230 $allowed_tags['optgroup'] = array(
231 'label' => true,
232 );
233 }
234
235 // Include dd, dt tags
236 if ( in_array( 'dd', $extra, true ) || in_array( 'all', $extra, true ) ) {
237 $allowed_tags['dd'] = array(
238 'class' => true,
239 'id' => true,
240 'style' => true,
241 );
242
243 $allowed_tags['dt'] = array(
244 'class' => true,
245 'id' => true,
246 'style' => true,
247 );
248 }
249
250 // Include forms tags.
251 if ( in_array( 'forms', $extra, true ) || in_array( 'all', $extra, true ) ) {
252 $tags = array( 'form', 'input', 'select', 'option', 'textarea', 'a' );
253
254 foreach ( $tags as $tag ) {
255 $allowed_tags[ $tag ] = array(
256 'id' => true,
257 'class' => true,
258 'style' => true,
259 'name' => true,
260 'href' => true,
261 'target' => true,
262 'value' => true,
263 'type' => true,
264 'placeholder' => true,
265 'data' => '*',
266 'data-source' => true,
267 'data-product_id' => true,
268 'data-product_variations' => true,
269 'data-attribute_name' => true,
270 'data-show_option_none' => true,
271 'data-name' => true,
272 'data-allowed-types' => true,
273 'step' => true,
274 'min' => true,
275 'max' => true,
276 'selected' => true,
277 'checked' => true,
278 'onchange' => true,
279 'autocomplete' => true,
280 'required' => true,
281 'action' => true,
282 'method' => true,
283 'enctype' => true,
284 'size' => true,
285 'role' => true,
286 'inputmode' => true,
287 'aria-label' => true,
288 'multiple' => true,
289 );
290
291 if ( $tag === 'a' ) {
292 $allowed_tags[ $tag ]['href'] = true;
293 $allowed_tags[ $tag ]['title'] = true;
294 $allowed_tags[ $tag ]['target'] = true;
295 }
296 }
297 }
298
299
300 // Include script tag
301 if ( in_array( 'script', $extra, true ) ) {
302 $allowed_tags['script'] = array(
303 'id' => true,
304 'src' => true,
305 'type' => true,
306 'async' => true,
307 'defer' => true,
308 );
309 }
310
311 if ( in_array( 'div', $extra, true ) ) {
312 $tags = array( 'form', 'input', 'select', 'option', 'textarea', 'a', 'div' );
313
314 foreach ( $tags as $tag ) {
315 $allowed_tags[ $tag ] = array(
316 'id' => true,
317 'class' => true,
318 'style' => true,
319 'name' => true,
320 'href' => true,
321 'target' => true,
322 'value' => true,
323 'type' => true,
324 'placeholder' => true,
325 'data' => '*',
326 'data-source' => true,
327 'data-product_id' => true,
328 'data-product_variations' => true,
329 'data-attribute_name' => true,
330 'data-show_option_none' => true,
331 'data-name' => true,
332 'data-allowed-types' => true,
333 'step' => true,
334 'min' => true,
335 'max' => true,
336 'selected' => true,
337 'checked' => true,
338 'onchange' => true,
339 'autocomplete' => true,
340 'required' => true,
341 'action' => true,
342 'method' => true,
343 'enctype' => true,
344 'size' => true,
345 'role' => true,
346 'inputmode' => true,
347 'aria-label' => true,
348 'multiple' => true,
349 'title' => true,
350 'data-id' => true,
351 'data-product-id' => true,
352 );
353
354 if ( $tag === 'a' ) {
355 $allowed_tags[ $tag ]['href'] = true;
356 $allowed_tags[ $tag ]['title'] = true;
357 $allowed_tags[ $tag ]['target'] = true;
358 }
359 }
360 }
361
362 /**
363 * Filters the allowed tags.
364 *
365 * @since 1.2.5
366 */
367 return apply_filters( 'merchant_kses_allowed_tags', $allowed_tags );
368 }
369 }
370
371 /**
372 * Allowed tags for scripts.
373 *
374 * @return array $allowed_tags
375 */
376 if ( ! function_exists( 'merchant_kses_allowed_tags_for_code_snippets' ) ) {
377 function merchant_kses_allowed_tags_for_code_snippets() {
378 return array(
379 'script' => array(
380 'type' => true,
381 ),
382 );
383 }
384 }
385
386 /**
387 * Check if WooCommerce checkout page is being rendered by block.
388 * Since WooCommerce 8.3.0 the checkout page is rendered by block.
389 *
390 * @return bool
391 */
392 if ( ! function_exists( 'merchant_is_checkout_block_layout' ) ) {
393 function merchant_is_checkout_block_layout() {
394 $checkout_page = wc_get_page_id( 'checkout' );
395
396 if ( empty( $checkout_page ) ) {
397 return false;
398 }
399
400 if ( function_exists( 'has_blocks' ) && has_blocks( $checkout_page ) ) {
401 $post = get_post( $checkout_page );
402 $blocks = parse_blocks( $post->post_content );
403
404 foreach ( $blocks as $block ) {
405 if ( 'woocommerce/checkout' === $block['blockName'] ) {
406 return true;
407 }
408 }
409 }
410
411 return false;
412 }
413 }
414
415 /**
416 * Check if WooCommerce cart page is being rendered by block.
417 * Since WooCommerce 8.3.0 the cart page is rendered by block.
418 *
419 * @return bool
420 */
421 if ( ! function_exists( 'merchant_is_cart_block_layout' ) ) {
422 function merchant_is_cart_block_layout() {
423 $cart_page = wc_get_page_id( 'cart' );
424
425 if ( empty( $cart_page ) ) {
426 return false;
427 }
428
429 if ( function_exists( 'has_blocks' ) && has_blocks( $cart_page ) ) {
430 $post = get_post( $cart_page );
431 $blocks = parse_blocks( $post->post_content );
432
433 foreach ( $blocks as $block ) {
434 if ( 'woocommerce/cart' === $block['blockName'] ) {
435 return true;
436 }
437 }
438 }
439
440 return false;
441 }
442 }
443
444 /**
445 * Get the product categories.
446 */
447 if ( ! function_exists( 'merchant_get_product_categories' ) ) {
448 function merchant_get_product_categories() {
449 $args = array(
450 'taxonomy' => 'product_cat',
451 'hide_empty' => false,
452 );
453
454 $categories = get_terms( $args );
455
456 $categories_tree = array();
457 $indexed_categories = array();
458
459 if ( ! empty( $categories ) && ! is_wp_error( $categories ) ) {
460 foreach ( $categories as $category ) {
461 $indexed_categories[ $category->term_id ] = array(
462 'id' => $category->term_id,
463 'slug' => $category->slug,
464 'name' => $category->name,
465 'parent' => $category->parent,
466 'children' => array(),
467 );
468 }
469
470 foreach ( $indexed_categories as &$cat ) {
471 if ( (int) $cat['parent'] === 0 ) {
472 $categories_tree[] = &$cat;
473 } else {
474 $indexed_categories[ $cat['parent'] ]['children'][] = &$cat;
475 }
476 }
477 }
478
479 return $categories_tree;
480 }
481 }
482
483 /**
484 * Get the product tags.
485 */
486 if ( ! function_exists( 'merchant_get_product_tags' ) ) {
487 function merchant_get_product_tags() {
488 $product_tags = get_terms( array(
489 'taxonomy' => 'product_tag',
490 'hide_empty' => false,
491 ) );
492
493 $tag_names = array();
494
495 if ( ! empty( $product_tags ) && ! is_wp_error( $product_tags ) ) {
496 foreach ( $product_tags as $tag ) {
497 $tag_names[ $tag->slug ] = $tag->name;
498 }
499 }
500
501 return $tag_names;
502 }
503 }
504
505 /**
506 * Convert array to css.
507 */
508 if ( ! function_exists( 'merchant_array_to_css' ) ) {
509 function merchant_array_to_css( $css_array ) {
510 $css = '';
511 if ( empty( $css_array ) ) {
512 return $css;
513 }
514 foreach ( $css_array as $key => $value ) {
515 $css .= $key . ':' . $value . ';';
516 }
517
518 return $css;
519 }
520 }
521
522 /**
523 * Get the share link data structure.
524 *
525 * @return array
526 */
527 if ( ! function_exists( 'merchant_get_share_link_data' ) ) {
528 function merchant_get_share_link_data() {
529 return array(
530 'facebook' => array(
531 'url' => 'https://www.facebook.com/sharer.php?u={{url}}',
532 'title' => __( 'Facebook', 'merchant' ),
533 ),
534 'twitter' => array(
535 'url' => 'https://twitter.com/intent/tweet?url={{url}}&text={{title}}',
536 'title' => __( 'X', 'merchant' ),
537 ),
538 'linkedin' => array(
539 'url' => 'https://www.linkedin.com/sharing/share-offsite/?url={{url}}',
540 'title' => __( 'LinkedIn', 'merchant' ),
541 ),
542 'reddit' => array(
543 'url' => 'https://reddit.com/submit?url={{url}}&title={{title}}',
544 'title' => __( 'Reddit', 'merchant' ),
545 ),
546 'whatsapp' => array(
547 'url' => 'https://api.whatsapp.com/send/?text={{url}}',
548 'title' => __( 'WhatsApp', 'merchant' ),
549 ),
550 'pinterest' => array(
551 'url' => 'http://pinterest.com/pin/create/link/?url={{url}}',
552 'title' => __( 'Pinterest', 'merchant' ),
553 ),
554 'telegram' => array(
555 'url' => 'https://t.me/share/url?url={{url}}&text={{title}}',
556 'title' => __( 'Telegram', 'merchant' ),
557 ),
558 'weibo' => array(
559 'url' => 'http://service.weibo.com/share/share.php?url={{url}}&appkey=&title={{title}}&pic=&ralateUid=',
560 'title' => __( 'Weibo', 'merchant' ),
561 ),
562 'vk' => array(
563 'url' => 'http://vk.com/share.php?url={{url}}&title={{title}}&comment={text}',
564 'title' => __( 'VK', 'merchant' ),
565 ),
566 'ok' => array(
567 'url' => 'https://connect.ok.ru/dk?st.cmd=WidgetSharePreview&st.shareUrl={{url}}',
568 'title' => __( 'OK', 'merchant' ),
569 ),
570 'xing' => array(
571 'url' => 'https://www.xing.com/spi/shares/new?url={{url}}',
572 'title' => __( 'Xing', 'merchant' ),
573 ),
574 'mail' => array(
575 'url' => 'mailto:?subject={{title}}&body={{url}}',
576 'title' => __( 'Mail', 'merchant' ),
577 ),
578 );
579 }
580 }
581
582 /**
583 * Get the share link url.
584 *
585 * @param string $social_network
586 *
587 * @return string
588 */
589 if ( ! function_exists( 'merchant_get_share_link_url' ) ) {
590 function merchant_get_share_link_url( $social_network, $url_to_share, $title_to_share = '' ) {
591 $share_link_data = merchant_get_share_link_data();
592
593 if ( ! isset( $share_link_data[ $social_network ] ) ) {
594 return '';
595 }
596
597 $share_link_url = str_replace(
598 array( '{{url}}', '{{title}}' ),
599 array( $url_to_share, $title_to_share ),
600 $share_link_data[ $social_network ]['url']
601 );
602
603 return $share_link_url;
604 }
605 }
606
607 /**
608 * Get the share link title.
609 *
610 * @param string $social_network
611 *
612 * @return string
613 */
614 if ( ! function_exists( 'merchant_get_share_link_title' ) ) {
615 function merchant_get_share_link_title( $social_network ) {
616 $share_link_data = merchant_get_share_link_data();
617
618 return isset( $share_link_data[ $social_network ] ) ? $share_link_data[ $social_network ]['title'] : '';
619 }
620 }
621
622 if ( ! function_exists( 'merchant_timezone' ) ) {
623 /**
624 * Get the WP timezone.
625 *
626 * @return string
627 */
628 function merchant_timezone() {
629 /**
630 * Filter the storewide sale timezone.
631 *
632 * @param string $timezone
633 *
634 * @since 1.9.9
635 */
636 return apply_filters(
637 'merchant_storewide_sale_timezone',
638 wp_timezone_string()
639 );
640 }
641 }
642
643 if ( ! function_exists( 'merchant_get_current_timestamp' ) ) {
644 /**
645 * Get the current timestamp.
646 *
647 * @return int|string
648 */
649 function merchant_get_current_timestamp() {
650 $timezone = new DateTimeZone( merchant_timezone() );
651
652 // Get the timestamp
653 return ( new DateTime( 'now', $timezone ) )->getTimestamp();
654 }
655 }
656
657 if ( ! function_exists( 'merchant_convert_date_to_timestamp' ) ) {
658 /**
659 * Convert date to timestamp.
660 *
661 * @param string $date The date to convert
662 * @param string $format The format of the date
663 *
664 * @return int The timestamp
665 */
666 function merchant_convert_date_to_timestamp( $date, $format = 'm-d-Y h:i A' ) {
667 $timezone = new DateTimeZone( merchant_timezone() );
668 $date_object = DateTime::createFromFormat( $format, $date, $timezone ); // Create DateTime object with specified format and timezone
669 if ( false === $date_object ) {
670 return 0;
671 }
672
673 return $date_object->getTimestamp(); // Output the timestamp
674 }
675 }
676
677 /**
678 * Parses a list of product IDs
679 * @return array
680 */
681 if ( ! function_exists( 'merchant_parse_product_ids' ) ) {
682 function merchant_parse_product_ids( $product_ids ) {
683 $parsed_ids = $product_ids ?? array();
684
685 // Convert to array if it's not already an array
686 $parsed_ids = ! is_array( $parsed_ids ) ? explode( ',', $parsed_ids ) : $parsed_ids;
687
688 // Convert all elements to integers
689 $parsed_ids = array_map( 'intval', $parsed_ids );
690
691 return $parsed_ids;
692 }
693 }
694
695 /**
696 * Check if the user condition is passed.
697 *
698 * @param $args
699 *
700 * @return bool
701 */
702 if ( ! function_exists( 'merchant_is_user_condition_passed' ) ) {
703 function merchant_is_user_condition_passed( $args = array() ) {
704 $passed = false;
705
706 $is_logged_in = is_user_logged_in();
707 $current_user = $is_logged_in ? wp_get_current_user() : null;
708
709 $condition = $args['user_condition'] ?? 'all';
710
711 switch ( $condition ) {
712 case 'all':
713 case '':
714 $passed = true;
715 break;
716
717 case 'logged-in':
718 if ( $is_logged_in ) {
719 $passed = true;
720 }
721 break;
722
723 case 'roles':
724 $roles = $args['user_condition_roles'] ?? array();
725 $role = $current_user->roles[0] ?? '';
726
727 if ( in_array( $role, $roles, true ) ) {
728 $passed = true;
729 }
730 break;
731
732 case 'customers':
733 $customers_id = $args['user_condition_users'] ?? array();
734 $customers_id = array_map( 'intval', $customers_id );
735 $customer_id = (int) ( $current_user->ID ?? 0 );
736
737 if ( in_array( $customer_id, $customers_id, true ) ) {
738 $passed = true;
739 }
740 break;
741 }
742
743 return $passed;
744 }
745 }
746
747 /**
748 * Check if a product is excluded based on given arguments.
749 *
750 * @param $product_id
751 * @param $args
752 *
753 * @return bool
754 */
755 if ( ! function_exists( 'merchant_is_product_excluded' ) ) {
756 function merchant_is_product_excluded( $product_id, $args = array() ) {
757 if ( empty( $args['exclusion_enabled'] ) ) {
758 return false;
759 }
760
761 $display_rule = $args['rules_to_display'] ?? $args['display_rules'] ?? $args['rules_to_apply'] ?? $args['trigger_on'] ?? 'products';
762
763 $rules = array(
764 'all',
765 'all_products',
766 'categories',
767 'category',
768 'by_category',
769 'tags',
770 'by_tags',
771 'featured_products',
772 'products_on_sale',
773 'new_products',
774 'out_of_stock',
775 'pre-order',
776 );
777
778 $product = wc_get_product( $product_id );
779 $_product_id = $product && $product->is_type( 'variation' ) ? $product->get_parent_id() : $product_id;
780
781 // Exclude products
782 if ( in_array( $display_rule, $rules, true ) ) {
783 $excluded_product_ids = $args['excluded_products'] ?? array();
784 $excluded_product_ids = merchant_parse_product_ids( $excluded_product_ids );
785
786 if ( in_array( (int) $product_id, $excluded_product_ids, true ) || in_array( (int) $_product_id, $excluded_product_ids, true ) ) {
787 return true;
788 }
789 }
790
791 // Exclude categories
792 if ( in_array( $display_rule, array( 'all', 'all_products' ), true ) ) {
793 $excluded_categories_slugs = $args['excluded_categories'] ?? array();
794
795 if ( ! empty( $excluded_categories_slugs ) && has_term( $excluded_categories_slugs, 'product_cat', $_product_id ) ) {
796 return true;
797 }
798 }
799
800 // Exclude tags
801 if ( in_array( $display_rule, array( 'all', 'all_products' ), true ) ) {
802 $excluded_tags_slugs = $args['excluded_tags'] ?? array();
803
804 if ( ! empty( $excluded_tags_slugs ) && has_term( $excluded_tags_slugs, 'product_tag', $_product_id ) ) {
805 return true;
806 }
807 }
808
809 return false;
810 }
811 }
812
813 /**
814 * Check if a product or any of its variations is excluded based on the given offer.
815 *
816 * This method determines if a product (simple or variable) or any of its variations
817 * satisfies the merchant exclusion rules.
818 *
819 * @param int $product_id The ID of the product to check.
820 * @param array $offer The offer data to evaluate against exclusion rules.
821 *
822 * @return bool True if the product or any of its variations is excluded, false otherwise.
823 */
824 if ( ! function_exists( 'merchant_is_product_or_variation_excluded' ) ) {
825 function merchant_is_product_or_variation_excluded( $product_id, $offer = array() ) {
826 $product = wc_get_product( $product_id );
827
828 if ( ! $product ) {
829 return false;
830 }
831
832 // Get IDs to check for exclusion
833 $product_ids = $product->is_type( 'variable' ) ? $product->get_children() : array( $product_id );
834
835 foreach ( $product_ids as $id ) {
836 if ( merchant_is_product_excluded( $id, $offer ) ) {
837 return true; // Excluded if any ID matches
838 }
839 }
840
841 return false;
842 }
843 }
844
845 /**
846 * Get the label of the first active payment gateway in WooCommerce.
847 *
848 * @return string|null The label of the first active payment gateway, or null if none are found.
849 */
850 if ( ! function_exists( 'merchant_get_first_active_payment_gateway_label' ) ) {
851 function merchant_get_first_active_payment_gateway_label() {
852 // Get the available payment gateways
853 $available_gateways = WC()->payment_gateways->get_available_payment_gateways();
854
855 // Check if there are any active gateways
856 if ( ! empty( $available_gateways ) ) {
857 // Get the first active gateway
858 return reset( $available_gateways )->get_title();
859 }
860
861 // Return null if no active gateways are found
862 return null;
863 }
864 }
865
866 /**
867 * Get the review count of a product.
868 *
869 * @param int $product_id The ID of the product to get the review count for.
870 *
871 * @return int The review count of the product.
872 */
873 if ( ! function_exists( 'merchant_get_product_reviews_count' ) ) {
874 function merchant_get_product_reviews_count( $product_id ) {
875 $product = wc_get_product( $product_id );
876
877 return $product ? $product->get_review_count() : 0;
878 }
879 }