PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 2.1.7
ShopBuilder – WooCommerce Builder For Elementor v2.1.7
3.4.2 3.4.1 3.4.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 All 63 releases
shopbuilder / app / Helpers / Fns.php

Fns.php in ShopBuilder – WooCommerce Builder For Elementor 2.1.7, at app/Helpers/Fns.php

2,677 lines 78.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Fns Helpers class
4 *
5 * @package RadiusTheme\SB
6 */
7
8 namespace RadiusTheme\SB\Helpers;
9
10 // Do not allow directly accessing this file.
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit( 'This script cannot be accessed directly.' );
13 }
14
15 use WC_Product;
16 use WC_Product_Query;
17 use Elementor\Icons_Manager;
18 use RadiusTheme\SB\Models\ReSizer;
19 use RadiusTheme\SB\Models\DataModel;
20 use RadiusTheme\SB\Models\ModuleList;
21 use RadiusTheme\SB\Models\Settings;
22
23 /**
24 * Fns class
25 */
26 class Fns {
27
28 /**
29 * @var array
30 */
31 private static $cache = [];
32
33 /**
34 * Verify nonce.
35 *
36 * @return bool
37 */
38 public static function verify_nonce() {
39 $nonce = isset( $_REQUEST[ rtsb()->nonceId ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ rtsb()->nonceId ] ) ) : null;
40 $nonceText = rtsb()->nonceText;
41 if ( wp_verify_nonce( $nonce, $nonceText ) ) {
42 return true;
43 }
44
45 return false;
46 }
47
48 /**
49 * @param $plugin_slug
50 *
51 * @return bool
52 */
53 public static function check_plugin_installed( $plugin_slug ): bool {
54 $installed_plugins = get_plugins();
55
56 return array_key_exists( $plugin_slug, $installed_plugins ) || in_array( $plugin_slug, $installed_plugins, true );
57 }
58
59 /**
60 * @param $plugin_slug
61 *
62 * @return bool
63 */
64 public static function check_plugin_active( $plugin_slug ): bool {
65 if ( is_plugin_active( $plugin_slug ) ) {
66 return true;
67 }
68
69 return false;
70 }
71
72 /**
73 * @param $data
74 *
75 * @return mixed|string
76 */
77 public static function stripslashes_value( $data ) {
78 if ( is_string( $data ) && strpos( $data, '\\' ) !== false ) {
79 return stripslashes( $data );
80 } elseif ( is_array( $data ) ) {
81 foreach ( $data as $key => $value ) {
82 $data[ $key ] = self::stripslashes_value( $value );
83 }
84 }
85
86 return $data;
87 }
88
89 /**
90 * @param $string
91 *
92 * @return array
93 */
94 public static function multiselect_settings_field_value( $string ) {
95
96 $values = [];
97 if ( empty( $string ) ) {
98 return $values;
99 }
100
101 $stripslashes_data = self::stripslashes_value( $string );
102 if ( is_array( $stripslashes_data ) && count( $stripslashes_data ) ) {
103 foreach ( $stripslashes_data as $item ) {
104 $item = is_array( $item ) ? $item : json_decode( $item, true );
105 $values[] = $item['value'];
106 }
107 }
108
109 return $values;
110 }
111
112 /**
113 * @return bool
114 */
115 public static function check_is_block_theme(): bool {
116 global $wp_version;
117
118 return version_compare( $wp_version, '5.9', '>=' ) && function_exists( 'wp_is_block_theme' ) && wp_is_block_theme();
119 }
120
121 /**
122 * @param string $template_name Template name.
123 * @param string $template_path Template path. (default: '').
124 * @param string $plugin_path Plugin path. (default: ''). fallback file from plugin
125 *
126 * @return mixed|void
127 */
128 public static function locate_template( $template_name, $template_path = '', $plugin_path = '' ) {
129 $template_name = $template_name . '.php';
130 if ( ! $template_path ) {
131 $template_path = rtsb()->get_template_path();
132 }
133 if ( ! $plugin_path ) {
134 $plugin_path = RTSB_ABSPATH . 'templates/';
135 }
136
137 $template_rtsb_path = trailingslashit( $template_path ) . $template_name;
138 $template_path = '/' . $template_name;
139 $plugin_path = $plugin_path . $template_name;
140 $pro_plugin_path = rtsb()->has_pro() ? RTSBPRO_PATH . 'templates/' . $template_name : '';
141
142 $located = locate_template(
143 apply_filters(
144 'rtsb/core/locate_template_files',
145 [
146 $template_rtsb_path, // Search in <theme>/shopbuilder/.
147 $template_path, // Search in <theme>/.
148 ]
149 )
150 );
151
152 if ( ! $located ) {
153 if ( file_exists( $plugin_path ) ) {
154 return apply_filters( 'rtsb/core/locate_template', $plugin_path, $template_name );
155 } elseif ( $pro_plugin_path && rtsb()->has_pro() && file_exists( $pro_plugin_path ) ) {
156 return apply_filters( 'rtsb/core/locate_template', $pro_plugin_path, $template_name );
157 }
158 }
159
160 /**
161 * APPLY_FILTERS: rtsb/core/locate_template
162 *
163 * Filter the location of the templates.
164 *
165 * @param string $located Template found
166 * @param string $path Template path
167 *
168 * @return string
169 */
170 return apply_filters( 'rtsb/core/locate_template', $located, $template_name );
171 }
172
173 /**
174 * Template Content
175 *
176 * @param string $template_name Template name.
177 * @param array $args Arguments. (default: array).
178 * @param bool $return Whether to return or print the template.
179 * @param string $template_path Template path. (default: '').
180 * @param string $plugin_path Fallback path from where file will load if fail to load from template. (default: '').
181 *
182 * @return false|string|void
183 */
184 public static function load_template( $template_name, array $args = null, $return = false, $template_path = '', $plugin_path = '' ) {
185 $located = self::locate_template( $template_name, $template_path, $plugin_path );
186
187 if ( ! file_exists( $located ) ) {
188 // translators: %s template.
189 self::doing_it_wrong( __FUNCTION__, sprintf( __( '%s does not exist.', 'shopbuilder' ), '<code>' . $located . '</code>' ), '1.0' );
190
191 return;
192 }
193
194 if ( ! empty( $args ) && is_array( $args ) ) {
195 $atts = $args;
196 extract( $args ); // @codingStandardsIgnoreLine
197 }
198
199 // Allow 3rd party plugin filter template file from their plugin.
200 $located = apply_filters( 'rtsb/core/get_template', $located, $template_name, $args );
201
202 if ( $return ) {
203 ob_start();
204 }
205
206 do_action( 'rtsb/core/before_template_part', $template_name, $located, $args );
207 include $located;
208
209 do_action( 'rtsb/core/after_template_part', $template_name, $located, $args );
210
211 if ( $return ) {
212 return ob_get_clean();
213 }
214 }
215
216 /**
217 * Verify nonce.
218 *
219 * @return string
220 */
221 public static function is_woocommerce() {
222 return is_woocommerce() || is_cart() || is_checkout() || is_account_page();
223 }
224
225 /**
226 * Page builder
227 *
228 * @param int $post_id post id.
229 *
230 * @return string
231 */
232 public static function page_edit_with( $post_id ) {
233 if ( ! $post_id ) {
234 return '';
235 }
236
237 $edit_with = get_post_meta( $post_id, '_elementor_edit_mode', true );
238
239 if ( 'builder' === $edit_with ) {
240 $edit_by = 'elementor';
241 } else {
242 $edit_by = 'gutenberg';
243 }
244
245 return $edit_by;
246 }
247
248 /**
249 * Returns default expiration for wishlist cookie
250 *
251 * @return int Number of seconds the cookie should last.
252 */
253 public static function get_cookie_expiration() {
254 return intval( apply_filters( 'rtsb/cookie_expiration', 60 * 60 * 24 * 30 ) );
255 }
256
257 /**
258 * Create a cookie.
259 *
260 * @param string $name Cookie name.
261 * @param mixed $value Cookie value.
262 * @param int $time Cookie expiration time.
263 * @param bool $secure Whether cookie should be available to secured connection only.
264 * @param bool $httponly Whether cookie should be available to HTTP request only (no js handling).
265 *
266 * @return bool
267 * @since 1.0.0
268 */
269 public static function setcookie( $name, $value = [], $time = null, $secure = false, $httponly = false ) {
270
271 if ( ! apply_filters( 'rtsb/set_cookie', true ) || empty( $name ) ) {
272 return false;
273 }
274
275 $time = ! empty( $time ) ? $time : time() + self::get_cookie_expiration();
276
277 $value = wp_json_encode( stripslashes_deep( $value ) );
278 $expiration = apply_filters( 'rtsb/cookie_expiration_time', $time ); // Default 30 days.
279
280 $_COOKIE[ $name ] = $value;
281 wc_setcookie( $name, $value, $expiration, $secure, $httponly );
282
283 return true;
284 }
285
286 /**
287 * Retrieve the value of a cookie.
288 *
289 * @param string $name Cookie name.
290 *
291 * @return mixed
292 * @since 1.0.0
293 */
294 public static function getcookie( $name ) {
295 if ( isset( $_COOKIE[ $name ] ) ) {
296 return json_decode( sanitize_text_field( wp_unslash( $_COOKIE[ $name ] ) ), true );
297 }
298
299 return [];
300 }
301
302 /**
303 * Woocommerce Last product id return
304 */
305 public static function get_prepared_product_id() {
306 if ( is_singular( 'product' ) ) {
307 return get_the_ID();
308 }
309 // Return the Builder Template id.
310
311 if ( get_post_type( get_the_ID() ) == BuilderFns::$post_type_tb ) {
312 $product_id = get_post_meta( get_the_ID(), BuilderFns::$product_template_meta, true );
313 if ( $product_id ) {
314 return $product_id;
315 }
316 }
317
318 global $wpdb;
319 $cache_key = 'rtsb_prepared_product_id';
320 $_post_id = wp_cache_get( $cache_key );
321
322 if ( false === $_post_id || 'publish' !== get_post_status( $_post_id ) ) {
323 $_post_id = $wpdb->get_var(
324 $wpdb->prepare( "SELECT MAX(ID) FROM {$wpdb->prefix}posts WHERE post_type = %s AND post_status IN('publish', 'draft')", 'product' )
325 );
326 wp_cache_set( $cache_key, $_post_id, '', 12 * HOUR_IN_SECONDS );
327 }
328
329 return $_post_id;
330 }
331
332 /**
333 * Get the product function. Only used in single page widgets.
334 *
335 * @return object
336 */
337 public static function get_product() {
338 global $product;
339
340 if ( is_singular( 'product' ) && $product instanceof WC_Product ) {
341 // do_action( 'rtsb_before_product_template_render' );.
342 return $product;
343 }
344 $cache_key = 'prepared_product_for_preview';
345 if ( isset( self::$cache[ $cache_key ] ) ) {
346 return self::$cache[ $cache_key ];
347 }
348 $product = wc_get_product( self::get_prepared_product_id() );
349 self::$cache[ $cache_key ] = $product;
350 do_action( 'rtsb_before_product_template_render' );
351 return $product;
352 }
353
354 /**
355 * Error function
356 *
357 * @param [type] $function function name.
358 * @param [type] $message message.
359 * @param [type] $version version.
360 *
361 * @return void
362 */
363 public static function doing_it_wrong( $function, $message, $version ) {
364 $message .= ' Backtrace: ' . wp_debug_backtrace_summary();
365 _doing_it_wrong( $function, $message, $version );
366 }
367
368 /**
369 * @return array
370 */
371 public static function get_pages() {
372 $pages = [];
373 $rawPages = get_pages();
374 if ( ! empty( $rawPages ) ) {
375 foreach ( $rawPages as $page ) {
376 $pages[ $page->ID ] = $page->post_title;
377 }
378 }
379
380 return $pages;
381 }
382
383 public static function get_section_items( $section_id ) {
384 if ( ! $section_id ) {
385 return [];
386 }
387
388 return DataModel::source()->get_option( $section_id, [] );
389 }
390
391 public static function get_options( $section_id, $item_id ) {
392 if ( ! $section_id || ! $item_id ) {
393 return [];
394 }
395 $sections = self::get_section_items( $section_id );
396
397 return isset( $sections[ $item_id ] ) ? $sections[ $item_id ] : [];
398 }
399
400 /**
401 * Get options value with default value if options doesn't exist.
402 *
403 * @param $group
404 * @param $option_key
405 * @param $default_value
406 *
407 * @return mixed|string
408 */
409 public static function get_options_by_default_val( $group, $option_key, $default_value = '' ) {
410
411 if ( ! $option_key || ! isset( $group[ $option_key ] ) ) {
412 return $default_value;
413 }
414
415 return $group[ $option_key ];
416 }
417
418 /**
419 * @param string $section_id
420 * @param string $item_id
421 * @param string $option_id
422 * @param null $default EXCEPT multi_checkbox you can provide default value if given option does not set any value
423 * @param null $type checkbox, multi_checkbox, number
424 *
425 * @return bool|int|mixed|null
426 */
427 public static function get_option( $section_id, $item_id, $option_id, $default = null, $type = null ) {
428 $options = self::get_options( $section_id, $item_id );
429
430 if ( $type === 'checkbox' ) {
431 if ( isset( $options[ $option_id ] ) ) {
432 return $options[ $option_id ] === 'on';
433 }
434
435 return $default;
436 } elseif ( $type === 'multi_checkbox' ) {
437 return isset( $options[ $option_id ] ) && is_array( $options[ $option_id ] ) && in_array( $default, $options[ $option_id ] );
438 } elseif ( $type === 'number' ) {
439 return isset( $options[ $option_id ] ) ? absint( $options[ $option_id ] ) : absint( $default );
440 }
441
442 return isset( $options[ $option_id ] ) && ! empty( $options[ $option_id ] ) ? $options[ $option_id ] : $default;
443 }
444
445
446 /**
447 * Create a page and store the ID in an option.
448 *
449 * @param mixed $slug Slug for the new page.
450 * @param array $options ['section_id', 'item_id', 'option_id']Option name to store the page's ID.
451 * @param string $page_title (default: '') Title for the new page.
452 * @param string $page_content (default: '') Content for the new page.
453 * @param int $post_parent (default: 0) Parent for the new page.
454 * @param string $post_status (default: publish) The post status of the new page.
455 *
456 * @return int page ID.
457 */
458 public static function create_page( $slug, $options = '', $page_title = '', $page_content = '', $post_parent = 0, $post_status = 'publish' ) {
459 global $wpdb;
460
461 $option_value = 0;
462 if ( ! empty( $options ) ) {
463 if ( is_array( $options ) ) {
464 $options = wp_parse_args(
465 $options,
466 [
467 'section_id' => '',
468 'item_id' => '',
469 'option_id' => '',
470 ]
471 );
472 $option_value = self::get_option( $options['section_id'], $options['item_id'], $options['option_id'], 0, 'number' );
473 } else {
474 $option_value = absint( get_option( $options ) );
475 }
476 }
477
478 if ( $option_value > 0 ) {
479 $page_object = get_post( $option_value );
480
481 if ( $page_object && 'page' === $page_object->post_type && ! in_array(
482 $page_object->post_status,
483 [
484 'pending',
485 'trash',
486 'future',
487 'auto-draft',
488 ],
489 true
490 ) ) {
491 // Valid page is already in place.
492 return $page_object->ID;
493 }
494 }
495
496 if ( strlen( $page_content ) > 0 ) {
497 // Search for an existing page with the specified page content (typically a shortcode).
498 $shortcode = str_replace( [ '<!-- wp:shortcode -->', '<!-- /wp:shortcode -->' ], '', $page_content );
499 $valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_content LIKE %s LIMIT 1;", "%{$shortcode}%" ) );
500 } else {
501 // Search for an existing page with the specified page slug.
502 $valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_name = %s LIMIT 1;", $slug ) );
503 }
504
505 $valid_page_found = apply_filters( 'rtsb/core/create_page_id', $valid_page_found, $slug, $page_content, $options );
506
507 if ( $valid_page_found ) {
508 if ( is_array( $options ) ) {
509 if ( ! empty( $options['section_id'] ) && $options['item_id'] && $options['option_id'] ) {
510 $section_items = DataModel::source()->get_option( $options['section_id'], [] );
511 $section_items[ $options['item_id'] ][ $options['option_id'] ] = $valid_page_found;
512 DataModel::source()->set_option( $options['section_id'], $section_items );
513 }
514 } else {
515 if ( $options ) {
516 update_option( $options, $valid_page_found );
517 }
518 }
519
520 return $valid_page_found;
521 }
522
523 // Search for a matching valid trashed page.
524 if ( strlen( $page_content ) > 0 ) {
525 // Search for an existing page with the specified page content (typically a shortcode).
526 $trashed_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status = 'trash' AND post_content LIKE %s LIMIT 1;", "%{$page_content}%" ) );
527 } else {
528 // Search for an existing page with the specified page slug.
529 $trashed_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status = 'trash' AND post_name = %s LIMIT 1;", $slug ) );
530 }
531
532 if ( $trashed_page_found ) {
533 $page_id = $trashed_page_found;
534 $page_data = [
535 'ID' => $page_id,
536 'post_status' => $post_status,
537 ];
538 wp_update_post( $page_data );
539 } else {
540 $page_data = [
541 'post_status' => $post_status,
542 'post_type' => 'page',
543 'post_author' => 1,
544 'post_name' => $slug,
545 'post_title' => $page_title,
546 'post_content' => $page_content,
547 'post_parent' => $post_parent,
548 'comment_status' => 'closed',
549 ];
550 $page_id = wp_insert_post( $page_data );
551
552 do_action( 'rtsb/core/page_created', $page_id, $page_data );
553 }
554
555 if ( is_array( $options ) ) {
556 if ( ! empty( $options['section_id'] ) && $options['item_id'] && $options['option_id'] ) {
557 $section_items = DataModel::source()->get_option( $options['section_id'], [] );
558 $section_items[ $options['item_id'] ][ $options['option_id'] ] = $page_id;
559 DataModel::source()->set_option( $options['section_id'], $section_items );
560 }
561 } else {
562 if ( $options ) {
563 update_option( $options, $page_id );
564 }
565 }
566
567 return $page_id;
568 }
569
570 public static function get_kses_array() {
571 return [
572 'a' => [
573 'class' => [],
574 'href' => [],
575 'rel' => [],
576 'title' => [],
577 ],
578 'abbr' => [
579 'title' => [],
580 ],
581 'b' => [],
582 'blockquote' => [
583 'cite' => [],
584 ],
585 'cite' => [
586 'title' => [],
587 ],
588 'code' => [],
589 'del' => [
590 'datetime' => [],
591 'title' => [],
592 ],
593 'dd' => [],
594 'div' => [
595 'class' => [],
596 'title' => [],
597 'style' => [],
598 ],
599 'dl' => [],
600 'dt' => [],
601 'em' => [],
602 'h1' => [
603 'class' => [],
604 ],
605 'h2' => [
606 'class' => [],
607 ],
608 'h3' => [
609 'class' => [],
610 ],
611 'h4' => [
612 'class' => [],
613 ],
614 'h5' => [
615 'class' => [],
616 ],
617 'h6' => [
618 'class' => [],
619 ],
620 'i' => [
621 'class' => [],
622 ],
623 'img' => [
624 'alt' => [],
625 'class' => [],
626 'height' => [],
627 'src' => [],
628 'width' => [],
629 ],
630 'li' => [
631 'class' => [],
632 ],
633 'ol' => [
634 'class' => [],
635 ],
636 'p' => [
637 'class' => [],
638 ],
639 'q' => [
640 'cite' => [],
641 'title' => [],
642 ],
643 'span' => [
644 'class' => [],
645 'title' => [],
646 'style' => [],
647 ],
648 'iframe' => [
649 'width' => [],
650 'height' => [],
651 'scrolling' => [],
652 'frameborder' => [],
653 'allow' => [],
654 'src' => [],
655 ],
656 'strike' => [],
657 'br' => [],
658 'strong' => [],
659 'data-wow-duration' => [],
660 'data-wow-delay' => [],
661 'data-wallpaper-options' => [],
662 'data-stellar-background-ratio' => [],
663 'ul' => [
664 'class' => [],
665 ],
666 ];
667 }
668
669
670 /*
671 * Escape output of wishlist icon
672 *
673 * @param string $data Data to escape.
674 * @return string Escaped data
675 */
676 public static function print_icon( $data ) {
677 /**
678 * APPLY_FILTERS: rtsb/core/allowed_icon_html
679 *
680 * Filter the allowed HTML for the icons.
681 *
682 * @param array $allowed_icon_html Allowed HTML
683 *
684 * @return array
685 */
686 $allowed_icon_html = apply_filters(
687 'rtsb/core/allowed_icon_html',
688 [
689 'i' => [
690 'class' => true,
691 ],
692 'img' => [
693 'src' => true,
694 'alt' => true,
695 'width' => true,
696 'height' => true,
697 ],
698 'svg' => [
699 'class' => true,
700 'aria-hidden' => true,
701 'aria-labelledby' => true,
702 'role' => true,
703 'xmlns' => true,
704 'width' => true,
705 'height' => true,
706 'viewbox' => true,
707 'stroke' => true,
708 'fill' => true,
709 ],
710 'g' => [
711 'fill' => true,
712 ],
713 'title' => [
714 'title' => true,
715 ],
716 'path' => [
717 'd' => true,
718 'fill' => true,
719 'stroke' => true,
720 'stroke-width' => true,
721 'stroke-linecap' => true,
722 'stroke-linejoin' => true,
723 'fill-rule' => true,
724 'clip-rule' => true,
725 ],
726 ]
727 );
728
729 echo wp_kses( $data, $allowed_icon_html );
730 }
731
732 /**
733 * Prints HTMl.
734 *
735 * @param string $html HTML.
736 * @param bool $allHtml All HTML.
737 *
738 * @return void
739 */
740 public static function print_html( $html, $allHtml = false ) {
741 if ( ! $html ) {
742 return;
743 }
744 if ( $allHtml ) {
745 echo stripslashes_deep( $html ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
746 } else {
747 echo wp_kses_post( stripslashes_deep( $html ) );
748 }
749 }
750
751 /**
752 * Allowed HTML for wp_kses.
753 *
754 * @param string $level Tag level.
755 *
756 * @return mixed
757 */
758 public static function allowedHtml( $level = 'basic' ) {
759 $allowed_html = [];
760 // TODO:: Need Optimize.
761 switch ( $level ) {
762 case 'basic':
763 $allowed_html = [
764 'b' => [
765 'class' => [],
766 'id' => [],
767 ],
768 'i' => [
769 'class' => [],
770 'id' => [],
771 ],
772 'u' => [
773 'class' => [],
774 'id' => [],
775 ],
776 'br' => [
777 'class' => [],
778 'id' => [],
779 ],
780 'em' => [
781 'class' => [],
782 'id' => [],
783 ],
784 'span' => [
785 'class' => [],
786 'id' => [],
787 ],
788 'strong' => [
789 'class' => [],
790 'id' => [],
791 ],
792 'hr' => [
793 'class' => [],
794 'id' => [],
795 ],
796 'div' => [
797 'class' => [],
798 'id' => [],
799 ],
800 'a' => [
801 'href' => [],
802 'title' => [],
803 'class' => [],
804 'id' => [],
805 'target' => [],
806 ],
807 ];
808 break;
809
810 case 'advanced':
811 $allowed_html = [
812 'b' => [
813 'class' => [],
814 'id' => [],
815 ],
816 'i' => [
817 'class' => [],
818 'id' => [],
819 ],
820 'u' => [
821 'class' => [],
822 'id' => [],
823 ],
824 'br' => [
825 'class' => [],
826 'id' => [],
827 ],
828 'em' => [
829 'class' => [],
830 'id' => [],
831 ],
832 'span' => [
833 'class' => [],
834 'id' => [],
835 ],
836 'strong' => [
837 'class' => [],
838 'id' => [],
839 ],
840 'hr' => [
841 'class' => [],
842 'id' => [],
843 ],
844 'a' => [
845 'href' => [],
846 'title' => [],
847 'class' => [],
848 'id' => [],
849 'target' => [],
850 ],
851 'input' => [
852 'type' => [],
853 'name' => [],
854 'class' => [],
855 'value' => [],
856 ],
857 ];
858 break;
859
860 case 'image':
861 $allowed_html = [
862 'img' => [
863 'src' => [],
864 'data-src' => [],
865 'alt' => [],
866 'height' => [],
867 'width' => [],
868 'class' => [],
869 'id' => [],
870 'style' => [],
871 'srcset' => [],
872 'loading' => [],
873 'sizes' => [],
874 ],
875 'div' => [
876 'class' => [],
877 ],
878 ];
879 break;
880
881 case 'anchor':
882 $allowed_html = [
883 'a' => [
884 'href' => [],
885 'title' => [],
886 'class' => [],
887 'id' => [],
888 'style' => [],
889 ],
890 ];
891 break;
892
893 default:
894 // code...
895 break;
896 }
897
898 return $allowed_html;
899 }
900
901 /**
902 * Safe print a validated HTML tag.
903 *
904 * @param string $tag
905 */
906 public static function print_validated_html_tag( $tag ) {
907 $allowed_html_wrapper_tags = [
908 'a',
909 'article',
910 'aside',
911 'button',
912 'div',
913 'footer',
914 'h1',
915 'h2',
916 'h3',
917 'h4',
918 'h5',
919 'h6',
920 'header',
921 'main',
922 'nav',
923 'p',
924 'section',
925 'span',
926 ];
927
928 self::print_html( in_array( strtolower( $tag ), $allowed_html_wrapper_tags, true ) ? $tag : 'div' );
929 }
930
931 /**
932 * Insert Some array element
933 *
934 * @param [type] $key The elements will insert nearby this key.
935 * @param [type] $main_array Original array.
936 * @param [type] $insert_array some element will insert in original array.
937 * @param boolean $is_after array insert position base on the key.
938 *
939 * @return array
940 */
941 public static function insert_controls( $key, $main_array, $insert_array, $is_after = false ) {
942 $index = array_search( $key, array_keys( $main_array ), true );
943 if ( 'integer' === gettype( $index ) ) {
944 if ( $is_after ) {
945 $index++;
946 }
947 $main_array = array_merge(
948 array_slice( $main_array, 0, $index ),
949 $insert_array,
950 array_slice( $main_array, $index )
951 );
952 }
953
954 return $main_array;
955 }
956
957 /**
958 * Image Sizes
959 *
960 * @return array
961 */
962 public static function get_image_sizes() {
963 global $_wp_additional_image_sizes;
964
965 $sizes = [];
966
967 foreach ( get_intermediate_image_sizes() as $_size ) {
968 if ( in_array( $_size, [ 'thumbnail', 'medium', 'large' ], true ) ) {
969 $sizes[ $_size ]['width'] = get_option( "{$_size}_size_w" );
970 $sizes[ $_size ]['height'] = get_option( "{$_size}_size_h" );
971 $sizes[ $_size ]['crop'] = (bool) get_option( "{$_size}_crop" );
972 } elseif ( isset( $_wp_additional_image_sizes[ $_size ] ) ) {
973 $sizes[ $_size ] = [
974 'width' => $_wp_additional_image_sizes[ $_size ]['width'],
975 'height' => $_wp_additional_image_sizes[ $_size ]['height'],
976 'crop' => $_wp_additional_image_sizes[ $_size ]['crop'],
977 ];
978 }
979 }
980
981 $imgSize = [];
982
983 foreach ( $sizes as $key => $img ) {
984 $imgSize[ $key ] = ucfirst( $key ) . " ({$img['width']}*{$img['height']})";
985 }
986
987 $imgSize['full'] = esc_html__( 'Full size', 'shopbuilder' );
988 $imgSize['rtsb_custom'] = esc_html__( 'Custom image size', 'shopbuilder' );
989
990 return $imgSize;
991 }
992
993 /**
994 * Free Layouts
995 *
996 * @return array
997 */
998 public static function free_layouts() {
999 $layouts = [
1000 'grid-layout1' => esc_html__( 'Grid Layout 1', 'shopbuilder' ),
1001 'grid-layout2' => esc_html__( 'Grid Layout 2', 'shopbuilder' ),
1002 'list-layout1' => esc_html__( 'List Layout 1', 'shopbuilder' ),
1003 'list-layout2' => esc_html__( 'List Layout 2', 'shopbuilder' ),
1004 'slider-layout1' => esc_html__( 'Slider Layout 1', 'shopbuilder' ),
1005 'slider-layout2' => esc_html__( 'Slider Layout 2', 'shopbuilder' ),
1006 'category-single-layout1' => esc_html__( 'Category Single Layout 1', 'shopbuilder' ),
1007 'category-layout1' => esc_html__( 'Category Layout 1', 'shopbuilder' ),
1008 'category-layout2' => esc_html__( 'Category Layout 2', 'shopbuilder' ),
1009 ];
1010
1011 return apply_filters( 'rtsb/elements/elementor/free_layouts', $layouts );
1012 }
1013
1014 /**
1015 * Get all terms by taxonomy
1016 *
1017 * @param string $taxonomy Taxonomy name.
1018 * @param bool $placeholder Placeholder..
1019 *
1020 * @return array
1021 */
1022 public static function get_all_terms( $taxonomy, $placeholder = false ) {
1023 $terms = [];
1024
1025 if ( empty( $taxonomy ) ) {
1026 return $terms;
1027 }
1028 $cache_key = 'rtsb_get_all_terms_by_tax_name_' . $taxonomy;
1029 if ( isset( self::$cache[ $cache_key ] ) ) {
1030 return self::$cache[ $cache_key ];
1031 }
1032
1033 $termList = get_terms( [ $taxonomy ], [ 'hide_empty' => 0 ] );
1034
1035 if ( is_array( $termList ) && ! empty( $termList ) && empty( $termList['errors'] ) ) {
1036 if ( $placeholder ) {
1037 $terms = [
1038 'all' => __( 'All Products', 'shopbuilder' ),
1039 ];
1040 }
1041
1042 foreach ( $termList as $term ) {
1043 $terms[ $term->term_id ] = esc_html( $term->name );
1044 }
1045 }
1046 self::$cache[ $cache_key ] = $terms;
1047 return $terms;
1048 }
1049
1050 /**
1051 * Get all terms by attributes
1052 *
1053 * @return array
1054 */
1055 public static function get_all_attributes() {
1056 $terms = [];
1057 $termList = [];
1058
1059 $attributes = wc_get_attribute_taxonomies();
1060
1061 if ( $attributes ) {
1062 foreach ( $attributes as $tax ) {
1063 if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) ) {
1064 $termList[ $tax->attribute_name ] = get_terms( wc_attribute_taxonomy_name( $tax->attribute_name ), 'orderby=name&hide_empty=0' );
1065 }
1066 }
1067 }
1068
1069 if ( ! empty( $termList ) && empty( $termList['errors'] ) && is_array( $termList ) ) {
1070 foreach ( $termList as $name => $atts ) {
1071 foreach ( $atts as $term ) {
1072 $terms[ $term->term_id ] = esc_html( ucwords( str_replace( '-', ' ', $name ) ) . ' - ' . $term->name );
1073 }
1074 }
1075 }
1076
1077 return $terms;
1078 }
1079
1080 /**
1081 * Get all attributes name
1082 *
1083 * @return array
1084 */
1085 public static function get_all_attributes_name() {
1086 $attributes_name = [];
1087
1088 $attributes = wc_get_attribute_taxonomies();
1089
1090 if ( $attributes ) {
1091 foreach ( $attributes as $tax ) {
1092 if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) ) {
1093 $attributes_name[ wc_attribute_taxonomy_name( $tax->attribute_name ) ] = ucwords( $tax->attribute_name );
1094 }
1095 }
1096 }
1097
1098 return $attributes_name;
1099 }
1100
1101 /**
1102 * Get User list
1103 *
1104 * @return array
1105 */
1106 public static function get_users() {
1107 $users = [];
1108 $u = get_users();
1109
1110 if ( ! empty( $u ) ) {
1111 foreach ( $u as $user ) {
1112 $users[ $user->ID ] = $user->display_name;
1113 }
1114 }
1115
1116 return $users;
1117 }
1118
1119 /**
1120 * Get Taxonomy List.
1121 *
1122 * @return array
1123 */
1124 public static function get_tax_list() {
1125 return apply_filters(
1126 'rtsb/elements/tax_list',
1127 [
1128 'product_cat' => esc_html__( 'Product Category', 'shopbuilder' ),
1129 ]
1130 );
1131 }
1132
1133 /**
1134 * Get Category Query List.
1135 *
1136 * @return array
1137 */
1138 public static function get_cat_list() {
1139 return [
1140 'all' => esc_html__( 'All Categories', 'shopbuilder' ),
1141 'specific_parent' => esc_html__( 'Sub-Categories by Parent', 'shopbuilder' ),
1142 'cat_ids' => esc_html__( 'Select by ID', 'shopbuilder' ),
1143 'selection' => esc_html__( 'Manual Selection', 'shopbuilder' ),
1144 ];
1145 }
1146
1147 /**
1148 * Get Term List.
1149 *
1150 * @param string $taxonomy Taxonomy.
1151 * @param bool $first_term First term.
1152 * @param bool $only_parents Only parent terms.
1153 * @param bool $return_slug Return with slug.
1154 *
1155 * @return int|array
1156 */
1157 public static function get_terms( $taxonomy, $first_term = false, $only_parents = false, $return_slug = false ) {
1158 if ( ! is_admin() ) {
1159 return [];
1160 }
1161
1162 // TODO:: Return Slug always true for all settings.
1163 $term_list = [];
1164 $args = [
1165 'taxonomy' => $taxonomy,
1166 'hide_empty' => false,
1167 ];
1168
1169 if ( $only_parents ) {
1170 $args['parent'] = 0;
1171 }
1172
1173 $terms = get_terms( $args );
1174
1175 if ( empty( $terms ) ) {
1176 return [ esc_html__( 'Nothing found', 'shopbuilder' ) ];
1177 }
1178
1179 foreach ( $terms as $term ) {
1180 if ( $return_slug ) {
1181 $term_list[ $term->slug ] = $term->name;
1182 } else {
1183 $term_list[ $term->term_id ] = $term->name;
1184 }
1185 }
1186
1187 if ( $first_term ) {
1188 return array_keys( $term_list )[0];
1189 } else {
1190 return $term_list;
1191 }
1192 }
1193
1194 /**
1195 * Get product rating.
1196 *
1197 * @param array $args Arguments.
1198 *
1199 * @return string|void
1200 */
1201 public static function get_product_rating_html( $args = [] ) {
1202 global $product;
1203
1204 $html = '';
1205 $rating_count = $product->get_rating_count();
1206 $average_rating = $product->get_average_rating();
1207
1208 if ( ! rtsb()->has_pro() || empty( $args ) ) {
1209 if ( ! $rating_count || empty( wc_get_rating_html( $average_rating, $rating_count ) ) ) {
1210 return $html;
1211 }
1212
1213 $html .= '<div class="product-rating">';
1214 $html .= wc_get_rating_html( $average_rating, $rating_count );
1215 $html .= ! empty( $html ) ? '<span class="rtsb-count">(' . $average_rating . ')</span>' : '';
1216 $html .= '</div>';
1217
1218 self::print_html( $html, true );
1219
1220 return;
1221 }
1222
1223 if ( empty( $rating_count ) && ! $args['show_empty_rating'] ) {
1224 return '';
1225 }
1226
1227 $preset = ! empty( $args['preset'] ) ? $args['preset'] : 'preset1';
1228 $average = $args['show_average_rating'] ? '<span class="rtsb-count">(' . $average_rating . ')</span>' : '';
1229 $count = '';
1230
1231 if ( $args['show_rating_count'] ) {
1232 $count .= '<div class="rtsb-count">';
1233 $count .= sprintf(
1234 /* translators: %s is the number of reviews */
1235 _n( '%s Review', '%s Reviews', $rating_count, 'shopbuilder' ),
1236 $rating_count
1237 );
1238 $count .= '</div>';
1239 }
1240
1241 if ( 'preset2' === $preset ) {
1242 $average = $args['show_average_rating'] ? '<div class="inner-wrapper"><span class="star-icon"></span><span class="average-rating">' . $average_rating . '</span></div>' : '';
1243 }
1244
1245 $html .= '<div class="product-rating ' . esc_attr( $preset ) . '">';
1246
1247 if ( 'preset1' === $preset ) {
1248 $html .= wc_get_rating_html( $average_rating, $rating_count );
1249 $html .= $average;
1250 $html .= $count;
1251 } elseif ( 'preset2' === $preset ) {
1252 $html .= $average;
1253 $html .= $count;
1254 }
1255
1256 $html .= '</div>';
1257
1258 self::print_html( $html, true );
1259 }
1260
1261 /**
1262 * Text truncation.
1263 *
1264 * @param string $text_to_truncate Text.
1265 * @param int $limit Limit.
1266 * @param string $after After text.
1267 *
1268 * @return string
1269 */
1270 public static function text_truncation( $text_to_truncate, $limit, $after = '&#8230;' ) {
1271 if ( empty( $limit ) ) {
1272 return $text_to_truncate;
1273 }
1274
1275 $limit++;
1276
1277 $text = '';
1278
1279 if ( mb_strlen( $text_to_truncate ) > $limit ) {
1280 $subex = mb_substr( wp_strip_all_tags( $text_to_truncate ), 0, $limit );
1281 $exwords = explode( ' ', $subex );
1282 $excut = - ( mb_strlen( $exwords[ count( $exwords ) - 1 ] ) );
1283
1284 if ( $excut < 0 ) {
1285 $text .= mb_substr( $subex, 0, $excut ) . $after;
1286 } else {
1287 $text .= $subex . $after;
1288 }
1289 } else {
1290 $text .= $text_to_truncate;
1291 }
1292
1293 return $text;
1294 }
1295
1296 /**
1297 * Promo Badge HTML
1298 *
1299 * @param string $text Text.
1300 * @param string $class Class.
1301 *
1302 * @return void
1303 */
1304 public static function get_badge_html( $text, $class = 'fill' ) {
1305 if ( self::is_module_active( 'product_badges' ) && 'rtsb_yes' === $text ) {
1306 do_action( 'rtsb/modules/product_badges/frontend/display' );
1307
1308 return;
1309 }
1310
1311 if ( empty( $text ) ) {
1312 return;
1313 }
1314 ob_start();
1315 ?>
1316
1317 <ul class="rtsb-promotion-list">
1318 <li class="rtsb-promotion-list-item">
1319 <span class="rtsb-tag-<?php echo ! empty( $class ) ? esc_attr( $class ) : ''; ?>"><?php echo esc_html( $text ); ?></span>
1320 </li>
1321 </ul>
1322
1323 <?php
1324 self::print_html( ob_get_clean() );
1325 }
1326
1327 /**
1328 * Categories HTML
1329 *
1330 * @param int $id Product ID.
1331 * @param string $class Custom class.
1332 *
1333 * @return void|string
1334 */
1335 public static function get_categories_list( $id, $class = 'rtsb-category-outline' ) {
1336 if ( empty( $id ) ) {
1337 return '';
1338 }
1339
1340 ob_start();
1341 ?>
1342
1343 <ul class="rtsb-category-list <?php echo esc_attr( $class ); ?>">
1344 <?php
1345 self::print_html(
1346 wc_get_product_category_list(
1347 $id,
1348 '</li><li class="rtsb-category-list-item">',
1349 '<li class="rtsb-category-list-item">',
1350 '</li>'
1351 )
1352 );
1353 ?>
1354 </ul>
1355
1356 <?php
1357 self::print_html( ob_get_clean() );
1358 }
1359
1360 /**
1361 * Get Featured Image HTML.
1362 *
1363 * @param string $type Image type.
1364 * @param int $post_id Post ID.
1365 * @param string $f_img_size Image size.
1366 * @param null $default_img_id Default image ID.
1367 * @param array $custom_img_size Custom image size.
1368 * @param bool $lazy Lazy load check.
1369 * @param bool $hover Hover image.
1370 * @param bool $gallery Gallery image.
1371 * @param bool $custom_image_id Custom category image ID.
1372 *
1373 * @return string|null
1374 */
1375 public static function get_product_image_html( $type = 'product', $post_id = null, $f_img_size = 'medium', $default_img_id = null, $custom_img_size = [], $lazy = false, $hover = false, $gallery = false, $custom_image_id = 0 ) {
1376 $img_html = null;
1377 $attachment_id = null;
1378 $c_size = false;
1379 $hover_class = '';
1380 $post_title = '';
1381
1382 if ( 'rtsb_custom' === $f_img_size ) {
1383 $f_img_size = 'full';
1384 $c_size = true;
1385 }
1386
1387 if ( ! rtsb()->has_pro() ) {
1388 $gallery = false;
1389 }
1390
1391 if ( $hover ) {
1392 $a_id = $post_id;
1393 $hover_class = ' rtsb-img-hover';
1394 } elseif ( $gallery ) {
1395 $a_id = $post_id;
1396 } else {
1397 if ( 'product' === $type ) {
1398 $a_id = get_post_thumbnail_id( $post_id );
1399 $post_title = get_the_title( $post_id );
1400 } elseif ( 'category' === $type ) {
1401 $a_id = $custom_image_id ? $custom_image_id : get_term_meta( $post_id, 'thumbnail_id', true );
1402 $post_title = get_term( $post_id )->name;
1403 } else {
1404 $a_id = $default_img_id;
1405 }
1406 }
1407
1408 $img_alt = trim( wp_strip_all_tags( get_post_meta( $a_id, '_wp_attachment_image_alt', true ) ) );
1409 $alt_tag = ! empty( $img_alt ) ? $img_alt : wp_strip_all_tags( $post_title );
1410 $lazy_class = $lazy ? ' swiper-lazy' : '';
1411 $attr = [
1412 'class' => 'img-responsive rtsb-product-image' . $lazy_class . $hover_class,
1413 'alt' => $alt_tag,
1414 ];
1415
1416 if ( $a_id ) {
1417 $img_html = wp_get_attachment_image( $a_id, $f_img_size, false, $attr );
1418 $attachment_id = $a_id;
1419 }
1420
1421 if ( ! $img_html && $default_img_id ) {
1422 $img_html = wp_get_attachment_image( $default_img_id, $f_img_size, false, $attr );
1423 $attachment_id = $default_img_id;
1424 }
1425
1426 if ( $img_html && $c_size ) {
1427 preg_match( '@src="([^"]+)"@', $img_html, $match );
1428 $img_src = array_pop( $match );
1429 $w = ! empty( $custom_img_size['width'] ) ? absint( $custom_img_size['width'] ) : null;
1430 $h = ! empty( $custom_img_size['height'] ) ? absint( $custom_img_size['height'] ) : null;
1431 $c = ! empty( $custom_img_size['crop'] ) && 'soft' === $custom_img_size['crop'] ? false : true;
1432
1433 if ( $w && $h ) {
1434 $image = self::image_resize( $img_src, $w, $h, $c, false );
1435
1436 if ( ! empty( $image ) ) {
1437 [ $src, $width, $height ] = $image;
1438
1439 $hwstring = image_hwstring( $width, $height );
1440 $attachment = get_post( $attachment_id );
1441 $attr = apply_filters( 'wp_get_attachment_image_attributes', $attr, $attachment, $f_img_size );
1442
1443 if ( $lazy ) {
1444 $attr['data-src'] = $src;
1445 } else {
1446 $attr['src'] = $src;
1447 }
1448
1449 $attr = array_map( 'esc_attr', $attr );
1450 $img_html = rtrim( "<img $hwstring" );
1451
1452 foreach ( $attr as $name => $value ) {
1453 $img_html .= " $name=" . '"' . $value . '"';
1454 }
1455
1456 $img_html .= ' />';
1457 }
1458 }
1459 }
1460
1461 if ( ! $img_html ) {
1462 $hwstring = image_hwstring( 160, 160 );
1463 $attr = isset( $attr['src'] ) ? apply_filters( 'wp_get_attachment_image_attributes', $attr, false, $f_img_size ) : [];
1464 $attr['class'] = 'default-img';
1465 $attr['src'] = esc_url( rtsb()->get_assets_uri( 'images/demo.png' ) );
1466 $attr['alt'] = esc_html__( 'Default Image', 'shopbuilder' );
1467 $img_html = rtrim( "<img $hwstring" );
1468
1469 foreach ( $attr as $name => $value ) {
1470 $img_html .= " $name=" . '"' . $value . '"';
1471 }
1472
1473 $img_html .= ' />';
1474 }
1475
1476 if ( $lazy ) {
1477 $img_html = $img_html . '<div class="swiper-lazy-preloader swiper-lazy-preloader"></div>';
1478 }
1479
1480 return $img_html;
1481 }
1482
1483 /**
1484 * Call the Image resize model for resize function
1485 *
1486 * @param string $url URL.
1487 * @param int $width Width.
1488 * @param int $height Height.
1489 * @param string $crop Crop.
1490 * @param bool|true $single Single.
1491 * @param bool|false $upscale Upscale.
1492 *
1493 * @return array|bool|string
1494 */
1495 public static function image_resize( $url, $width = null, $height = null, $crop = null, $single = true, $upscale = false ) {
1496 $rtResize = new ReSizer();
1497
1498 return $rtResize->process( $url, $width, $height, $crop, $single, $upscale );
1499 }
1500
1501 /**
1502 * Get Product Image
1503 *
1504 * @param string $f_image Featured Image.
1505 * @param string $h_image Hover Image.
1506 *
1507 * @return void
1508 */
1509 public static function get_product_image( $f_image, $h_image = null ) {
1510 if ( empty( $f_image ) ) {
1511 return;
1512 }
1513
1514 echo wp_kses( $f_image, self::allowedHtml( 'image' ) );
1515
1516 if ( ! empty( $h_image ) ) {
1517 echo wp_kses( $h_image, self::allowedHtml( 'image' ) );
1518 }
1519 }
1520
1521 /**
1522 * Post Custom Field value.
1523 *
1524 * @param int $post_id Post id.
1525 * @param string $field_key Custom Field Key.
1526 * @param string $field_fallback FallBack text.
1527 *
1528 * @return string|void
1529 */
1530 public static function get_post_custom_field_value( $post_id, $field_key = '', $field_fallback = '' ) {
1531 if ( ! $post_id || ! $field_key ) {
1532 return;
1533 }
1534 $field_value = get_post_meta( $post_id, $field_key, true );
1535 if ( empty( $field_value ) ) {
1536 $field_value = ! empty( $field_fallback ) ? $field_fallback : $field_value;
1537 }
1538 $field_value = apply_filters( 'rtsb/get_post_custom_field_value/' . $field_key, $field_value, $field_key );
1539
1540 return sprintf( '<span class="rtsb-woo-custom-field">%s</span>', $field_value );
1541 }
1542
1543 /**
1544 * Elementor Icon
1545 *
1546 * @param array $control Elementor Control array.
1547 * @param string $class Custom class.
1548 * @param string $builder Builder name.
1549 *
1550 * @return string
1551 */
1552 public static function icons_manager( $control, $class = '', $builder = 'elementor' ): string {
1553 if ( empty( $control['value'] ) ) {
1554 return '';
1555 }
1556 if ( is_array( $control['value'] ) ) {
1557 $cache_key = 'icons_managet_' . str_replace( ' ', '', md5( serialize( $control['value'] ) ) );
1558 } else {
1559 $cache_key = 'icons_managet_' . str_replace( ' ', '', $control['value'] );
1560 }
1561 if ( isset( self::$cache[ $cache_key ] ) ) {
1562 return self::$cache[ $cache_key ];
1563 }
1564
1565 $attributes = [
1566 'aria-hidden' => 'true',
1567 ];
1568
1569 if ( ! empty( $class ) ) {
1570 $attributes['class'] = esc_attr( $class );
1571 }
1572
1573 ob_start();
1574
1575 if ( defined( 'ELEMENTOR_VERSION' ) && ! empty( $control ) && 'elementor' === $builder ) {
1576 Icons_Manager::render_icon( $control, $attributes );
1577 }
1578
1579 $icons = ob_get_clean();
1580 self::$cache[ $cache_key ] = $icons;
1581 return $icons;
1582 }
1583
1584 /**
1585 * Get product swatches.
1586 *
1587 * @param string $type Swatch type.
1588 *
1589 * @return void
1590 */
1591 public static function get_product_swatches( $type ) {
1592 ?>
1593 <div class="rtsb-swatches <?php echo esc_attr( $type ); ?>-layout">
1594 <?php
1595 do_action( 'rtwpvs_show_archive_variation' );
1596 ?>
1597 </div>
1598 <?php
1599 }
1600
1601 /**
1602 * Get sale badge
1603 *
1604 * @param string $type Badge type.
1605 * @param string $text Badge text.
1606 * @param string $out_of_stock_text Out of stock text.
1607 *
1608 * @return string
1609 */
1610 public static function get_sale_badge( $type, $text, $out_of_stock_text ) {
1611 global $product;
1612
1613 if ( ! $product->is_in_stock() ) {
1614 return $out_of_stock_text;
1615 }
1616
1617 if ( ! $product->is_on_sale() ) {
1618 return '';
1619 }
1620
1621 $badge_text = '';
1622 $percentage = self::calculate_sale_percentage( $product );
1623
1624 if ( $percentage > 0 ) {
1625 $badge_text = '-' . round( $percentage ) . '%';
1626 }
1627
1628 if ( 'text' === $type ) {
1629 $badge_text = $text;
1630 }
1631
1632 return $badge_text;
1633 }
1634
1635 /**
1636 * Get sale badge
1637 *
1638 * @param object $product Product Object.
1639 * @param string $type Badge type.
1640 * @param string $text Badge text.
1641 * @param string $out_of_stock_text Out of stock text.
1642 *
1643 * @return string
1644 */
1645 public static function get_promo_badge( $product, $type, $text, $out_of_stock_text ) {
1646 $disable_badges = self::get_option( 'general', 'guest_user', 'hide_badges', '' );
1647 $badges_visibility = rtsb()->has_pro() && ! is_user_logged_in() && $disable_badges;
1648
1649 if ( $badges_visibility ) {
1650 return '';
1651 }
1652
1653 if ( is_null( $product ) ) {
1654 global $product;
1655 }
1656
1657 if ( ! $product instanceof WC_Product ) {
1658 return '';
1659 }
1660
1661 if ( ! $product->is_in_stock() ) {
1662 return $out_of_stock_text;
1663 }
1664
1665 if ( ! $product->is_on_sale() ) {
1666 return '';
1667 }
1668
1669 $badge_text = '';
1670 $percentage = self::calculate_sale_percentage( $product );
1671
1672 if ( $percentage > 0 ) {
1673 $badge_text = '-' . round( $percentage ) . '%';
1674 }
1675
1676 if ( 'text' === $type ) {
1677 $badge_text = $text;
1678 }
1679
1680 return $badge_text;
1681 }
1682
1683 /**
1684 * Calculate Sale Percentage
1685 *
1686 * @param object $product Product object.
1687 *
1688 * @return float|int|string
1689 */
1690 public static function calculate_sale_percentage( $product = null ) {
1691 if ( is_null( $product ) ) {
1692 global $product;
1693 }
1694
1695 if ( ! $product instanceof WC_Product ) {
1696 return '';
1697 }
1698
1699 if ( ! $product->is_on_sale() ) {
1700 return '';
1701 }
1702
1703 $percentage = null;
1704 $max_percentage = '';
1705
1706 if ( $product->is_type( 'simple' ) ) {
1707 $max_percentage = ( ( $product->get_regular_price() - $product->get_sale_price() ) / $product->get_regular_price() ) * 100;
1708 } elseif ( $product->is_type( 'variable' ) ) {
1709 $max_percentage = 0;
1710
1711 foreach ( $product->get_children() as $child_id ) {
1712
1713 $variation = wc_get_product( $child_id );
1714
1715 $price = $variation->get_regular_price();
1716 $sale = $variation->get_sale_price();
1717
1718 if ( 0 !== $price && ! empty( $sale ) ) {
1719 $percentage = ( $price - $sale ) / $price * 100;
1720 }
1721
1722 if ( $percentage > $max_percentage ) {
1723 $max_percentage = $percentage;
1724 }
1725 }
1726 }
1727
1728 if ( $max_percentage > 0 ) {
1729 return round( $max_percentage );
1730 }
1731
1732 return 0;
1733 }
1734
1735 /**
1736 * Pagination
1737 *
1738 * @param string $pages Pages.
1739 * @param integer $range Range.
1740 * @param boolean $ajax Ajax.
1741 *
1742 * @return string
1743 */
1744 public static function custom_pagination( $pages = '', $range = 4, $ajax = false ) {
1745 $html = null;
1746 $showitems = ( $range * 2 ) + 1;
1747
1748 global $paged;
1749
1750 if ( is_front_page() ) {
1751 $paged = ( get_query_var( 'page' ) ) ? get_query_var( 'page' ) : 1;
1752 } else {
1753 $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
1754 }
1755
1756 if ( empty( $paged ) ) {
1757 $paged = 1;
1758 }
1759
1760 if ( '' === $pages ) {
1761 global $wp_query;
1762
1763 $pages = $wp_query->max_num_pages;
1764
1765 if ( ! $pages ) {
1766 $pages = 1;
1767 }
1768 }
1769
1770 $ajaxClass = null;
1771 $dataAttr = null;
1772
1773 if ( $ajax ) {
1774 $ajaxClass = ' rtsb-pagination-ajax';
1775 $dataAttr = "data-paged='1'";
1776 }
1777
1778 if ( 1 !== $pages ) {
1779 $html .= '<div class="rtsb-pagination' . $ajaxClass . '" ' . $dataAttr . '>';
1780 $html .= '<ul class="pagination-list">';
1781
1782 if ( $paged > 2 && $paged > $range + 1 && $showitems < $pages ) {
1783 $html .= "<li><a data-paged='1' href='" . get_pagenum_link( 1 ) . "' aria-label='First'>&laquo;</a></li>";
1784 }
1785
1786 if ( $paged > 1 && $showitems < $pages ) {
1787 $p = $paged - 1;
1788 $html .= "<li><a data-paged='{$p}' href='" . get_pagenum_link( $p ) . "' aria-label='Previous'>&lsaquo;</a></li>";
1789 }
1790
1791 for ( $i = 1; $i <= $pages; $i++ ) {
1792 if ( 1 != $pages && ( ! ( $i >= $paged + $range + 1 || $i <= $paged - $range - 1 ) || $pages <= $showitems ) ) {
1793 $html .= ( $paged == $i ) ? '<li class="active"><span>' . $i . '</span></li>' : "<li><a data-paged='{$i}' href='" . get_pagenum_link( $i ) . "'>" . $i . '</a></li>';
1794 }
1795 }
1796
1797 if ( $paged < $pages && $showitems < $pages ) {
1798 $p = $paged + 1;
1799 $html .= "<li><a data-paged='{$p}' href=\"" . get_pagenum_link( $paged + 1 ) . "\" aria-label='Next'>&rsaquo;</a></li>";
1800 }
1801
1802 if ( $paged < $pages - 1 && $paged + $range - 1 < $pages && $showitems < $pages ) {
1803 $html .= "<li><a data-paged='{$pages}' href='" . get_pagenum_link( $pages ) . "' aria-label='Last'>&raquo;</a></li>";
1804 }
1805
1806 $html .= '</ul>';
1807 $html .= '</div>';
1808 }
1809
1810 return $html;
1811 }
1812
1813 /**
1814 * Action Buttons HTMl
1815 *
1816 * @param array $items Items.
1817 * @param array $ajax_cart Ajax cart HTML.
1818 * @param string $preset Button preset.
1819 * @param array $position Position.
1820 * @param string $placement Placement.
1821 *
1822 * @return void|string
1823 */
1824 public static function get_formatted_action_buttons( $items, $ajax_cart = '', $preset = 'preset1', $position = 'above', $placement = 'top' ) {
1825 if ( empty( $items ) ) {
1826 return;
1827 }
1828
1829 $html = '';
1830 $class = '';
1831 $args = [ $items, $ajax_cart, $preset, $position, $placement ];
1832
1833 if ( ( 'top' === $placement && 'after' === $position ) || ( 'bottom' === $placement && 'above' === $position ) ) {
1834 return apply_filters( 'rtsb/elements/elementor/formatted_action_buttons', $html, $args );
1835 }
1836
1837 if ( 'preset2' === $preset ) {
1838 $class = 'rtsb-action-buttons-vertical vertical-delay-effect ' . $preset;
1839 } elseif ( 'preset4' === $preset ) {
1840 $class = 'rtsb-action-buttons-vertical rtsb-action-buttons-vertical-left vertical-delay-effect ' . $preset;
1841 } elseif ( 'preset1' === $preset || 'preset3' === $preset ) {
1842 $class = 'rtsb-action-buttons-cart-box-width-auto horizontal-floating-btn ' . $preset;
1843 }
1844
1845 if ( 'after' === $position && 'preset1' === $preset ) {
1846 $class .= ' after-content';
1847 }
1848
1849 if ( 'preset3' === $preset ) {
1850 $html .= '<div class="rtsb-action-buttons top-part ' . esc_attr( $preset ) . '">';
1851 $html .= '<ul class="rtsb-action-button-list">';
1852
1853 ob_start();
1854 /**
1855 * Additional formatted action buttons hook.
1856 */
1857 do_action( 'rtsb/elements/elementor/additional_action_buttons', $items );
1858 $html .= ob_get_clean();
1859
1860 $html .= self::get_action_button_by_type( $items, 'wishlist' );
1861 $html .= self::get_action_button_by_type( $items, 'compare' );
1862 $html .= self::get_action_button_by_type( $items, 'quick_view' );
1863 $html .= '</ul>';
1864 $html .= '</div>';
1865 $html .= '<div class="rtsb-action-buttons bottom-part ' . esc_attr( $preset ) . '">';
1866 $html .= '<ul class="rtsb-action-button-list">';
1867 $html .= self::get_action_button_by_type( $items, 'add_to_cart', $ajax_cart );
1868 $html .= '</ul>';
1869 $html .= '</div>';
1870 } elseif ( 'preset1' === $preset || 'preset2' === $preset || 'preset4' === $preset ) {
1871 $html .= '<div class="rtsb-action-buttons ' . esc_attr( $class ) . '">';
1872 $html .= '<ul class="rtsb-action-button-list">';
1873 $html .= self::get_action_button_by_type( $items, 'add_to_cart', $ajax_cart );
1874
1875 ob_start();
1876 /**
1877 * Additional formatted action buttons hook.
1878 */
1879 do_action( 'rtsb/elements/elementor/additional_action_buttons', $items );
1880 $html .= ob_get_clean();
1881
1882 $html .= self::get_action_button_by_type( $items, 'wishlist' );
1883 $html .= self::get_action_button_by_type( $items, 'compare' );
1884 $html .= self::get_action_button_by_type( $items, 'quick_view' );
1885 $html .= '</ul>';
1886 $html .= '</div>';
1887 }
1888
1889 return apply_filters( 'rtsb/elements/elementor/formatted_action_buttons', $html, $args );
1890 }
1891
1892 /**
1893 * Get Action Button HTML
1894 *
1895 * @param array $items Items.
1896 * @param string $type Button type.
1897 * @param string $cart_html Ajax cart HTML.
1898 * @param string $wrapper Wrapper tag.
1899 *
1900 * @return void|string
1901 */
1902 public static function get_action_button_by_type( $items, $type, $cart_html = '', $wrapper = 'li' ) {
1903 if ( ! in_array( $type, $items, true ) ) {
1904 return;
1905 }
1906
1907 $html = '';
1908 $class = 'rtsb-action-button-item';
1909
1910 if ( 'add_to_cart' === $type ) {
1911 $class .= ' rtsb-cart' . ( empty( $cart_html ) ? esc_attr( ' no-cart-button' ) : '' );
1912 } else {
1913 $class .= ' rtsb-' . esc_attr( str_replace( '_', '-', $type ) );
1914 }
1915
1916 $html .= '<' . esc_attr( $wrapper ) . ' class="' . esc_attr( $class ) . '">';
1917
1918 if ( ( 'add_to_cart' === $type ) && ( ! empty( $cart_html ) ) ) {
1919 $html .= $cart_html;
1920 } else {
1921 $html .= shortcode_exists( 'rtsb_' . $type . '_button' ) ? do_shortcode( '[rtsb_' . $type . '_button]' ) : null;
1922 }
1923
1924 $html .= '</' . esc_attr( $wrapper ) . '>';
1925
1926 return apply_filters( 'rtsb/elements/elementor/get_action_button_by_type', $html );
1927 }
1928
1929 /**
1930 * Social Share Platforms.
1931 *
1932 * @return mixed|null
1933 */
1934 public static function social_share_platforms_list() {
1935 return apply_filters(
1936 'rtsb/settings/social_share/platforms',
1937 [
1938 [
1939 'value' => 'facebook',
1940 'label' => esc_html__( 'Facebook', 'shopbuilder' ),
1941 ],
1942 [
1943 'value' => 'twitter',
1944 'label' => esc_html__( 'Twitter', 'shopbuilder' ),
1945 ],
1946 [
1947 'value' => 'linkedin',
1948 'label' => esc_html__( 'Linkedin', 'shopbuilder' ),
1949 ],
1950 [
1951 'value' => 'pinterest',
1952 'label' => esc_html__( 'Pinterest', 'shopbuilder' ),
1953 ],
1954 [
1955 'value' => 'skype',
1956 'label' => esc_html__( 'Skype', 'shopbuilder' ),
1957 ],
1958 [
1959 'value' => 'whatsapp',
1960 'label' => esc_html__( 'Whatsapp', 'shopbuilder' ),
1961 ],
1962 [
1963 'value' => 'reddit',
1964 'label' => esc_html__( 'Reddit', 'shopbuilder' ),
1965 ],
1966 [
1967 'value' => 'telegram',
1968 'label' => esc_html__( 'Telegram', 'shopbuilder' ),
1969 ],
1970 ]
1971 );
1972 }
1973
1974 /**
1975 * Get Social Share link HTML.
1976 *
1977 * @param int $id Post ID.
1978 * @param array $types Preset type.
1979 * @param string $preset Style type.
1980 * @param boolean $show_icon Show icon.
1981 * @param boolean $show_text Show text.
1982 *
1983 * @return string
1984 */
1985 public static function get_social_share_html( int $id, array $types, string $preset = 'default', $show_icon = true, $show_text = true ) {
1986 $attr = [ 'postid' => $id ];
1987 $output = '';
1988
1989 if ( empty( $types ) ) {
1990 return $output;
1991 }
1992
1993 foreach ( $types as $type ) {
1994 $link = [];
1995 $link['type'] = $type['share_items'];
1996 $link['class'] = '';
1997 $link['img'] = apply_filters( 'rtsb/elements/share/default_img', '', $id, $link );
1998
1999 if ( 'site' === $id ) {
2000 $link['url'] = home_url();
2001 $link['title'] = wp_strip_all_tags( get_bloginfo( 'name' ) );
2002 } elseif ( 0 === strpos( $id, 'http' ) ) {
2003 $link['url'] = $id;
2004 $link['title'] = '';
2005 } else {
2006 $link['url'] = get_permalink( $id );
2007 $link['title'] = wp_strip_all_tags( get_the_title( $id ) );
2008
2009 if ( has_post_thumbnail( $id ) ) {
2010 $link['img'] = wp_get_attachment_image_url( get_post_thumbnail_id( $id ), 'full' );
2011 }
2012
2013 $link['img'] = apply_filters( 'rtsb/elements/share/single_img', $link['img'], $id, $link );
2014 }
2015
2016 $link['url'] = apply_filters( 'rtsb/elements/share/url', $link['url'], $link );
2017
2018 switch ( $type['share_items'] ) {
2019 case 'facebook':
2020 $link['link'] = esc_url( 'https://www.facebook.com/sharer/sharer.php?u=' . $link['url'] . '&display=popup&ref=plugin&src=share_button' );
2021 $link['icon'] = '<svg xmlns="http://www.w3.org/2000/svg" width="18.8125" height="32" viewBox="0 0 602 1024"><path d="M548 6.857v150.857h-89.714q-49.143 0-66.286 20.571t-17.143 61.714v108h167.429l-22.286 169.143h-145.143v433.714h-174.857v-433.714h-145.714v-169.143h145.714v-124.571q0-106.286 59.429-164.857t158.286-58.571q84 0 130.286 6.857z"></path></svg>';
2022 $link['attr_title'] = esc_html__( 'Share on Facebook', 'shopbuilder' );
2023 $link['social_network'] = 'Facebook';
2024 $link['social_action'] = 'Share';
2025 break;
2026 case 'twitter':
2027 $link['link'] = esc_url( 'https://twitter.com/intent/tweet?text=' . htmlspecialchars( rawurlencode( html_entity_decode( $link['title'], ENT_COMPAT, 'UTF-8' ) ), ENT_COMPAT, 'UTF-8' ) . '&url=' . $link['url'] );
2028 $link['icon'] = '<svg width="24" height="24" viewBox="0 0 1200 1227" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M714.163 519.284L1160.89 0H1055.03L667.137 450.887L357.328 0H0L468.492 681.821L0 1226.37H105.866L515.491 750.218L842.672 1226.37H1200L714.137 519.284H714.163ZM569.165 687.828L521.697 619.934L144.011 79.6944H306.615L611.412 515.685L658.88 583.579L1055.08 1150.3H892.476L569.165 687.854V687.828Z" /></svg>';
2029 $link['attr_title'] = esc_html__( 'Share on Twitter', 'shopbuilder' );
2030 $link['social_network'] = 'Twitter';
2031 $link['social_action'] = 'Tweet';
2032 break;
2033 case 'pinterest':
2034 $link['link'] = esc_url( 'https://pinterest.com/pin/create/button/?url=' . $link['url'] . '&media=' . $link['img'] . '&description=' . $link['title'] );
2035 $link['icon'] = '<svg xmlns="http://www.w3.org/2000/svg" width="22.84375" height="32" viewBox="0 0 731 1024"><path d="M0 341.143q0-61.714 21.429-116.286t59.143-95.143 86.857-70.286 105.714-44.571 115.429-14.857q90.286 0 168 38t126.286 110.571 48.571 164q0 54.857-10.857 107.429t-34.286 101.143-57.143 85.429-82.857 58.857-108 22q-38.857 0-77.143-18.286t-54.857-50.286q-5.714 22.286-16 64.286t-13.429 54.286-11.714 40.571-14.857 40.571-18.286 35.714-26.286 44.286-35.429 49.429l-8 2.857-5.143-5.714q-8.571-89.714-8.571-107.429 0-52.571 12.286-118t38-164.286 29.714-116q-18.286-37.143-18.286-96.571 0-47.429 29.714-89.143t75.429-41.714q34.857 0 54.286 23.143t19.429 58.571q0 37.714-25.143 109.143t-25.143 106.857q0 36 25.714 59.714t62.286 23.714q31.429 0 58.286-14.286t44.857-38.857 32-54.286 21.714-63.143 11.429-63.429 3.714-56.857q0-98.857-62.571-154t-163.143-55.143q-114.286 0-190.857 74t-76.571 187.714q0 25.143 7.143 48.571t15.429 37.143 15.429 26 7.143 17.429q0 16-8.571 41.714t-21.143 25.714q-1.143 0-9.714-1.714-29.143-8.571-51.714-32t-34.857-54-18.571-61.714-6.286-60.857z"></path></svg>';
2036 $link['attr_title'] = esc_html__( 'Share on Pinterest', 'shopbuilder' );
2037 $link['social_network'] = 'Pinterest';
2038 $link['social_action'] = 'Pin';
2039 break;
2040 case 'linkedin':
2041 $link['link'] = esc_url( 'https://www.linkedin.com/shareArticle?url=' . $link['url'] . '&title=' . $link['title'] );
2042 $link['icon'] = '<svg xmlns="http://www.w3.org/2000/svg" width="27.4375" height="32" viewBox="0 0 878 1024"><path d="M199.429 357.143v566.286h-188.571v-566.286h188.571zM211.429 182.286q0.571 41.714-28.857 69.714t-77.429 28h-1.143q-46.857 0-75.429-28t-28.571-69.714q0-42.286 29.429-70t76.857-27.714 76 27.714 29.143 70zM877.714 598.857v324.571h-188v-302.857q0-60-23.143-94t-72.286-34q-36 0-60.286 19.714t-36.286 48.857q-6.286 17.143-6.286 46.286v316h-188q1.143-228 1.143-369.714t-0.571-169.143l-0.571-27.429h188v82.286h-1.143q11.429-18.286 23.429-32t32.286-29.714 49.714-24.857 65.429-8.857q97.714 0 157.143 64.857t59.429 190z"></path></svg>';
2043 $link['attr_title'] = esc_html__( 'Share on LinkedIn', 'shopbuilder' );
2044 $link['social_network'] = 'LinkedIn';
2045 $link['social_action'] = 'Share';
2046 break;
2047 case 'skype':
2048 $link['link'] = esc_url( 'https://web.skype.com/share?url=' . $link['url'] );
2049 $link['icon'] = '<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve" class="eapps-social-share-buttons-item-icon"> <path d="M23.016,13.971c0.111-0.638,0.173-1.293,0.173-1.963 c0-6.213-5.014-11.249-11.199-11.249c-0.704,0-1.393,0.068-2.061,0.193C8.939,0.348,7.779,0,6.536,0C2.926,0,0,2.939,0,6.565 c0,1.264,0.357,2.443,0.973,3.445c-0.116,0.649-0.18,1.316-0.18,1.999c0,6.212,5.014,11.25,11.198,11.25 c0.719,0,1.419-0.071,2.099-0.201C15.075,23.656,16.229,24,17.465,24C21.074,24,24,21.061,24,17.435 C24,16.163,23.639,14.976,23.016,13.971z M12.386,19.88c-3.19,0-6.395-1.453-6.378-3.953c0.005-0.754,0.565-1.446,1.312-1.446 c1.877,0,1.86,2.803,4.85,2.803c2.098,0,2.814-1.15,2.814-1.95c0-2.894-9.068-1.12-9.068-6.563c0-2.945,2.409-4.977,6.196-4.753 c3.61,0.213,5.727,1.808,5.932,3.299c0.102,0.973-0.543,1.731-1.662,1.731c-1.633,0-1.8-2.188-4.613-2.188 c-1.269,0-2.341,0.53-2.341,1.679c0,2.402,9.014,1.008,9.014,6.295C18.441,17.882,16.012,19.88,12.386,19.88z"></path> </svg>';
2050 $link['attr_title'] = esc_html__( 'Share on Skype', 'shopbuilder' );
2051 $link['social_network'] = 'Skype';
2052 $link['social_action'] = 'Skype';
2053 break;
2054 case 'whatsapp':
2055 $link['link'] = esc_url( 'https://wa.me/?text=' . $link['title'] . ' ' . $link['url'] );
2056 $link['icon'] = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-whatsapp" viewBox="0 0 16 16"> <path d="M13.601 2.326A7.854 7.854 0 0 0 7.994 0C3.627 0 .068 3.558.064 7.926c0 1.399.366 2.76 1.057 3.965L0 16l4.204-1.102a7.933 7.933 0 0 0 3.79.965h.004c4.368 0 7.926-3.558 7.93-7.93A7.898 7.898 0 0 0 13.6 2.326zM7.994 14.521a6.573 6.573 0 0 1-3.356-.92l-.24-.144-2.494.654.666-2.433-.156-.251a6.56 6.56 0 0 1-1.007-3.505c0-3.626 2.957-6.584 6.591-6.584a6.56 6.56 0 0 1 4.66 1.931 6.557 6.557 0 0 1 1.928 4.66c-.004 3.639-2.961 6.592-6.592 6.592zm3.615-4.934c-.197-.099-1.17-.578-1.353-.646-.182-.065-.315-.099-.445.099-.133.197-.513.646-.627.775-.114.133-.232.148-.43.05-.197-.1-.836-.308-1.592-.985-.59-.525-.985-1.175-1.103-1.372-.114-.198-.011-.304.088-.403.087-.088.197-.232.296-.346.1-.114.133-.198.198-.33.065-.134.034-.248-.015-.347-.05-.099-.445-1.076-.612-1.47-.16-.389-.323-.335-.445-.34-.114-.007-.247-.007-.38-.007a.729.729 0 0 0-.529.247c-.182.198-.691.677-.691 1.654 0 .977.71 1.916.81 2.049.098.133 1.394 2.132 3.383 2.992.47.205.84.326 1.129.418.475.152.904.129 1.246.08.38-.058 1.171-.48 1.338-.943.164-.464.164-.86.114-.943-.049-.084-.182-.133-.38-.232z"/> </svg>';
2057 $link['attr_title'] = esc_html__( 'Share on Whatsapp', 'shopbuilder' );
2058 $link['social_network'] = 'Whatsapp';
2059 $link['social_action'] = 'Share';
2060 break;
2061 case 'reddit':
2062 $link['link'] = esc_url( 'https://reddit.com/submit?url=' . $link['url'] . '&title=' . $link['title'] );
2063 $link['icon'] = '<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><title>ionicons-v5_logos</title><path d="M324,256a36,36,0,1,0,36,36A36,36,0,0,0,324,256Z"/><circle cx="188" cy="292" r="36" transform="translate(-97.43 94.17) rotate(-22.5)"/><path d="M496,253.77c0-31.19-25.14-56.56-56-56.56a55.72,55.72,0,0,0-35.61,12.86c-35-23.77-80.78-38.32-129.65-41.27l22-79L363.15,103c1.9,26.48,24,47.49,50.65,47.49,28,0,50.78-23,50.78-51.21S441,48,413,48c-19.53,0-36.31,11.19-44.85,28.77l-90-17.89L247.05,168.4l-4.63.13c-50.63,2.21-98.34,16.93-134.77,41.53A55.38,55.38,0,0,0,72,197.21c-30.89,0-56,25.37-56,56.56a56.43,56.43,0,0,0,28.11,49.06,98.65,98.65,0,0,0-.89,13.34c.11,39.74,22.49,77,63,105C146.36,448.77,199.51,464,256,464s109.76-15.23,149.83-42.89c40.53-28,62.85-65.27,62.85-105.06a109.32,109.32,0,0,0-.84-13.3A56.32,56.32,0,0,0,496,253.77ZM414,75a24,24,0,1,1-24,24A24,24,0,0,1,414,75ZM42.72,253.77a29.6,29.6,0,0,1,29.42-29.71,29,29,0,0,1,13.62,3.43c-15.5,14.41-26.93,30.41-34.07,47.68A30.23,30.23,0,0,1,42.72,253.77ZM390.82,399c-35.74,24.59-83.6,38.14-134.77,38.14S157,423.61,121.29,399c-33-22.79-51.24-52.26-51.24-83A78.5,78.5,0,0,1,75,288.72c5.68-15.74,16.16-30.48,31.15-43.79a155.17,155.17,0,0,1,14.76-11.53l.3-.21,0,0,.24-.17c35.72-24.52,83.52-38,134.61-38s98.9,13.51,134.62,38l.23.17.34.25A156.57,156.57,0,0,1,406,244.92c15,13.32,25.48,28.05,31.16,43.81a85.44,85.44,0,0,1,4.31,17.67,77.29,77.29,0,0,1,.6,9.65C442.06,346.77,423.86,376.24,390.82,399Zm69.6-123.92c-7.13-17.28-18.56-33.29-34.07-47.72A29.09,29.09,0,0,1,440,224a29.59,29.59,0,0,1,29.41,29.71A30.07,30.07,0,0,1,460.42,275.1Z"/><path d="M323.23,362.22c-.25.25-25.56,26.07-67.15,26.27-42-.2-66.28-25.23-67.31-26.27h0a4.14,4.14,0,0,0-5.83,0l-13.7,13.47a4.15,4.15,0,0,0,0,5.89h0c3.4,3.4,34.7,34.23,86.78,34.45,51.94-.22,83.38-31.05,86.78-34.45h0a4.16,4.16,0,0,0,0-5.9l-13.71-13.47a4.13,4.13,0,0,0-5.81,0Z"/></svg>';
2064 $link['attr_title'] = esc_html__( 'Share on Reddit', 'shopbuilder' );
2065 $link['social_network'] = 'Reddit';
2066 $link['social_action'] = 'Share';
2067 break;
2068 case 'telegram':
2069 $link['link'] = esc_url( 'https://telegram.me/share/url?text=' . $link['title'] . '&url=' . $link['url'] );
2070 $link['icon'] = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-telegram" viewBox="0 0 16 16"> <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8.287 5.906c-.778.324-2.334.994-4.666 2.01-.378.15-.577.298-.595.442-.03.243.275.339.69.47l.175.055c.408.133.958.288 1.243.294.26.006.549-.1.868-.32 2.179-1.471 3.304-2.214 3.374-2.23.05-.012.12-.026.166.016.047.041.042.12.037.141-.03.129-1.227 1.241-1.846 1.817-.193.18-.33.307-.358.336a8.154 8.154 0 0 1-.188.186c-.38.366-.664.64.015 1.088.327.216.589.393.85.571.284.194.568.387.936.629.093.06.183.125.27.187.331.236.63.448.997.414.214-.02.435-.22.547-.82.265-1.417.786-4.486.906-5.751a1.426 1.426 0 0 0-.013-.315.337.337 0 0 0-.114-.217.526.526 0 0 0-.31-.093c-.3.005-.763.166-2.984 1.09z"/> </svg>';
2071 $link['attr_title'] = esc_html__( 'Share on Telegram', 'shopbuilder' );
2072 $link['social_network'] = 'Telegram';
2073 $link['social_action'] = 'Share';
2074 break;
2075 }
2076
2077 $link['label'] = $type['share_text'];
2078 $link['target'] = '_blank';
2079 $link['rel'] = 'nofollow noopener noreferrer';
2080
2081 $data = '';
2082 $link = apply_filters( 'rtsb/elements/share/share_link', $link, $id, $preset );
2083 $icon = apply_filters( 'rtsb/elements/share/share_icon', $link['icon'], $preset );
2084 $target = ! empty( $link['target'] ) ? ' target="' . esc_attr( $link['target'] ) . '" ' : '';
2085 $rel = ! empty( $link['rel'] ) ? ' rel="' . esc_attr( $link['rel'] ) . '" ' : '';
2086 $attr_title = ! empty( $link['attr_title'] ) ? ' title="' . esc_attr( $link['attr_title'] ) . '" ' : '';
2087 $elements = [];
2088
2089 // Add classes.
2090 $css_classes = [
2091 'rtsb-share-btn',
2092 sanitize_html_class( $link['type'] ),
2093 ];
2094 $css_classes = array_merge( $css_classes, explode( ' ', $link['class'] ) );
2095 $css_classes = array_map( 'sanitize_html_class', $css_classes );
2096 $css_classes = implode( ' ', array_filter( $css_classes ) );
2097
2098 unset( $attr['pin-do'], $attr['action'] );
2099
2100 if ( 'pinterest' === $type['share_items'] ) {
2101 $attr['pin-do'] = 'none';
2102 }
2103
2104 if ( 'whatsapp' === $type['share_items'] ) {
2105 $attr['action'] = 'share/whatsapp/share';
2106 }
2107
2108 $attr = apply_filters( 'rtsb/elements/share/link_data', $attr, $link, $id );
2109
2110 if ( ! empty( $attr ) ) {
2111 foreach ( $attr as $key => $val ) {
2112 $data .= ' data-' . sanitize_html_class( $key ) . '="' . esc_attr( $val ) . '"';
2113 }
2114 }
2115
2116 $additional_attr = apply_filters( 'rtsb/elements/share/additional_attr', [], $link, $id, $preset );
2117
2118 if ( ! empty( $additional_attr ) ) {
2119 $attr_output = join( ' ', $additional_attr );
2120
2121 if ( ! empty( $data ) ) {
2122 $attr_output = ' ' . $attr_output;
2123 }
2124
2125 $data .= $attr_output;
2126 }
2127
2128 $elements['wrapper_start'] = sprintf(
2129 '<li class="rtsb-share-item"><a href="%s"%s%s%s class="%s"%s>',
2130 ! empty( $link['link'] ) ? esc_attr( $link['link'] ) : '',
2131 $attr_title,
2132 $target,
2133 $rel,
2134 $css_classes,
2135 $data
2136 );
2137 $elements['wrapper_end'] = '</a></li>';
2138
2139 $elements['icon'] = $show_icon ? '<span class="rtsb-share-icon">' . ( ! empty( $icon ) ? $icon : null ) . '</span>' : null;
2140 $elements['label'] = $show_text && ! empty( $link['label'] ) ? '<span class="rtsb-share-label">' . $link['label'] . '</span>' : null;
2141 $elements['icon_label'] = '<span class="rtsb-share-icon-label">' . $elements['icon'] . $elements['label'] . '</span>';
2142 $elements = apply_filters( 'rtsb/elements/share/output_elements', $elements, $link, $id );
2143
2144 $output .= $elements['wrapper_start'] . $elements['icon_label'] . $elements['wrapper_end'];
2145 }
2146
2147 return apply_filters( 'rtsb/elements/share/list_output', $output );
2148 }
2149
2150 /**
2151 * Social Share Platforms.
2152 *
2153 * @return mixed|null
2154 */
2155 public static function is_module_active( $module ) {
2156 $modulelist = ModuleList::instance()->get_data();
2157 if ( ! empty( $modulelist[ $module ]['active'] ) ) {
2158 return true;
2159 }
2160 }
2161
2162
2163 /***
2164 * Save Settings data
2165 *
2166 * @param $section_id
2167 * @param $block_id
2168 * @param $rawOptions
2169 *
2170 * @return array
2171 */
2172 public static function set_options( $section_id = '', $block_id = '', $rawOptions = [] ) {
2173 $section_id = ! empty( $section_id ) ? sanitize_text_field( wp_unslash( $section_id ) ) : '';
2174 $block_id = ! empty( $block_id ) ? sanitize_text_field( wp_unslash( $block_id ) ) : '';
2175 $rawOptions = ! empty( $rawOptions ) ? $rawOptions : [];
2176
2177 $results = [
2178 'status' => true,
2179 'message' => '',
2180 ];
2181 if ( ! $section_id || ! $block_id ) {
2182 $results['status'] = false;
2183 $results['message'] = esc_html__( 'Section , block or options may be empty', 'shopbuilder' );
2184
2185 return $results;
2186 }
2187 $sections = Settings::instance()->get_sections();
2188 if ( empty( $sections[ $section_id ] ) || empty( $sections[ $section_id ]['list'][ $block_id ] ) ) {
2189 $results['status'] = false;
2190 $results['message'] = esc_html__( 'No section or block found with given data', 'shopbuilder' );
2191
2192 return $results;
2193 }
2194
2195 $options = DataModel::source()->get_option( $section_id, [], false );
2196 $changed = false;
2197 $fields = [];
2198 if ( isset( $sections[ $section_id ]['list'][ $block_id ]['fields'] ) && ! empty( $sections[ $section_id ]['list'][ $block_id ]['fields'] ) ) {
2199 $fields = $sections[ $section_id ]['list'][ $block_id ]['fields'];
2200 }
2201
2202 if ( empty( $fields ) ) {
2203 if ( isset( $rawOptions['active'] ) ) {
2204 $changed = true;
2205 $options[ $block_id ]['active'] = 'on' === $rawOptions['active'] ? 'on' : '';
2206 }
2207 } else {
2208 foreach ( $rawOptions as $raw_option_key => $raw_value ) {
2209 if ( $raw_option_key === 'active' ) {
2210 $changed = true;
2211 $options[ $block_id ]['active'] = $sections[ $section_id ]['list'][ $block_id ]['active'] = 'on' === $raw_value ? 'on' : '';
2212 } else {
2213 if ( isset( $fields[ $raw_option_key ] ) ) {
2214 $field = $fields[ $raw_option_key ];
2215 if ( $field['type'] === 'switch' ) {
2216 $value = 'on' === $raw_value ? 'on' : '';
2217 } elseif ( 'repeaters' === $field['type'] ) {
2218 $value = stripslashes_deep( $raw_value );
2219 } else {
2220 if ( ! empty( $field['multiple'] ) || in_array( $field['type'], [ 'checkbox', 'search_and_multi_select' ] ) ) {
2221
2222 if ( isset( $raw_value ) && is_array( $raw_value ) ) {
2223 if ( ! empty( $field['sanitize_fn'] ) && is_callable( $field['sanitize_fn'] ) ) {
2224 $value = array_map( $field['sanitize_fn'], $raw_value );
2225 } else {
2226 $value = array_map( 'sanitize_text_field', $raw_value );
2227 }
2228 } else {
2229 $value = [];
2230 }
2231 } else {
2232 if ( ! empty( $field['sanitize_fn'] ) && is_callable( $field['sanitize_fn'] ) ) {
2233 $value = $field['sanitize_fn']( $raw_value );
2234 } else {
2235 $value = sanitize_text_field( $raw_value );
2236 }
2237 }
2238 }
2239 $options[ $block_id ][ $raw_option_key ] = $sections[ $section_id ]['list'][ $block_id ]['fields'][ $raw_option_key ]['value'] = $value ?? null;
2240 $changed = true;
2241 }
2242 }
2243 }
2244 }
2245 if ( ! $changed ) {
2246 $results['status'] = false;
2247 $results['message'] = esc_html__( 'No changes found for update', 'shopbuilder' );
2248
2249 return $results;
2250 }
2251
2252 DataModel::source()->set_option( $section_id, $options );
2253
2254 $results['status'] = true;
2255 $results['message'] = esc_html__( 'Successfully Saved', 'shopbuilder' );
2256 $results['sections'] = $sections;
2257
2258 return $results;
2259 }
2260
2261 /***
2262 * @param $meta_key
2263 * @param $meta_value
2264 *
2265 * @return mixed|void
2266 *
2267 *
2268 * public static function get_post_id_by_meta_key_and_value( $meta_key, $meta_value ) {
2269 * if( ! $meta_key || ! $meta_value ){
2270 * return;
2271 * }
2272 * global $wpdb;
2273 * $prepare_guery = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '%s' and meta_value = '%d'", $meta_key, $meta_value );
2274 * $the_products = $wpdb->get_col( $prepare_guery );
2275 * if( count( $the_products ) > 0 ){
2276 * return $the_products[0];
2277 * }
2278 * return;
2279 * }
2280 */
2281 public static function count_products_by_taxonomies( $terms, $taxonomy = 'product_cat' ) {
2282 if ( empty( $terms ) || ! is_array( $terms ) ) {
2283 return;
2284 }
2285
2286 $args = [
2287 'limit' => -1,
2288 'return' => 'ids',
2289 ];
2290
2291 if ( 'product_cat' === $taxonomy ) {
2292 $args['product_category_id'] = $terms;
2293 } else {
2294 $args['product_tag_id'] = $terms;
2295 }
2296
2297 $query = new WC_Product_Query( $args );
2298
2299 return ! empty( $query->get_products() ) ? count( $query->get_products() ) : 0;
2300 }
2301
2302 /**
2303 * Check if product filters widget has ajax.
2304 *
2305 * @param string $page Page name.
2306 *
2307 * @return bool
2308 */
2309 public static function product_filters_has_ajax( $page ) {
2310 if ( empty( $page ) ) {
2311 return false;
2312 }
2313
2314 if ( 'page' === get_post_type() ) {
2315 return false;
2316 }
2317
2318 $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page );
2319 if ( ! $id ) {
2320 return false;
2321 }
2322 $cache_key = 'product_filters_has_ajax_' . $id;
2323 if ( isset( self::$cache[ $cache_key ] ) ) {
2324 return self::$cache[ $cache_key ];
2325 }
2326 $elmap = ElementorDataMap::instance();
2327 $ajax = [];
2328
2329 foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) {
2330 $ajax[] = isset( $data['settings']['ajax_mode'] ) ? false : true;
2331 }
2332 self::$cache[ $cache_key ] = ! empty( $ajax[0] );
2333 return ! empty( $ajax[0] );
2334 }
2335
2336 /**
2337 * Check if product has applied filter.
2338 *
2339 * @param string $page Page name.
2340 *
2341 * @return bool
2342 */
2343 public static function product_has_applied_filters( $page ) {
2344 if ( empty( $page ) ) {
2345 return false;
2346 }
2347
2348 $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page );
2349 $elmap = ElementorDataMap::instance();
2350 $ajax = [];
2351 if ( ! $id ) {
2352 return false;
2353 }
2354 foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) {
2355 $ajax[] = ! isset( $data['settings']['active_filter'] );
2356
2357 }
2358
2359 return ! empty( $ajax[0] );
2360 }
2361
2362 /**
2363 * Get WooCommerce product categories.
2364 *
2365 * @param string|null $search_query The search string for category names.
2366 *
2367 * @return array An array of product categories with 'value' and 'label' keys.
2368 */
2369 public static function products_category_query( $search_query = null ) {
2370 if ( ! is_admin() ) {
2371 return [];
2372 }
2373
2374 $cache_key = 'rtsb_product_categories_' . md5( serialize( $search_query ) );
2375
2376 if ( isset( self::$cache[ $cache_key ] ) ) {
2377 return self::$cache[ $cache_key ];
2378 }
2379
2380 $results = wp_cache_get( $cache_key );
2381
2382 if ( ! $results ) {
2383 global $wpdb;
2384 $sql = "SELECT t.term_id, t.name
2385 FROM {$wpdb->terms} t
2386 JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
2387 WHERE tt.taxonomy = 'product_cat'";
2388
2389 if ( $search_query ) {
2390 $sql .= ' AND t.name LIKE %s';
2391 $prepared_sql = $wpdb->prepare( $sql, '%' . $wpdb->esc_like( $search_query ) . '%' ); // Escaping and wildcard
2392 } else {
2393 $prepared_sql = $sql; // No need for placeholders.
2394 }
2395
2396 $results = $wpdb->get_results( $prepared_sql );
2397 // Cache the results in the object cache for future use.
2398 wp_cache_set( $cache_key, $results ); // Adjust the expiration time as needed.
2399 }
2400
2401 $cats = [];
2402 if ( ! is_array( $results ) && ! count( $results ) ) {
2403 return $cats;
2404 }
2405 foreach ( $results as $row ) {
2406 $category_id = $row->term_id;
2407 $category_title = $row->name;
2408
2409 $cats[] = [
2410 'value' => $category_id,
2411 'label' => $category_title,
2412 ];
2413 }
2414
2415 // Cache the results in a static variable for the next call.
2416 self::$cache[ $cache_key ] = $cats;
2417 return $cats;
2418 }
2419
2420 /**
2421 * @param string $search_query Search query.
2422 *
2423 * @return array
2424 */
2425 public static function get_registered_post_types( $search_query = null ) {
2426 // Get all registered post types.
2427 $registered_post_types = get_post_types(
2428 [
2429 'public' => true,
2430 '_builtin' => false,
2431 ],
2432 'objects'
2433 );
2434
2435 unset( $registered_post_types['elementor_library'] );
2436 unset( $registered_post_types['e-landing-page'] );
2437 unset( $registered_post_types['rtsb_builder'] );
2438
2439 $post_types = [];
2440
2441 // Check if a search query is provided.
2442 if ( ! empty( $search_query ) ) {
2443 // Filter post types based on the search query.
2444 $registered_post_types = array_filter(
2445 $registered_post_types,
2446 function ( $post_type ) use ( $search_query ) {
2447 return stripos( $post_type->labels->singular_name, $search_query ) !== false;
2448 }
2449 );
2450 // Check if 'post' match the search query and include them if they do.
2451 if ( stripos( 'post', $search_query ) !== false ) {
2452 $post_types[] = [
2453 'value' => 'post',
2454 'label' => 'Post',
2455 ];
2456 }
2457 } else {
2458 $post_types[] = [
2459 'value' => 'post',
2460 'label' => 'Post',
2461 ];
2462 }
2463
2464 // Convert the filtered post types to an array.
2465 foreach ( $registered_post_types as $post_type ) {
2466 $post_types[] = [
2467 'value' => $post_type->name,
2468 'label' => $post_type->labels->singular_name,
2469 ];
2470 }
2471
2472 return $post_types;
2473 }
2474
2475 /**
2476 * Get Post Types.
2477 *
2478 * @param string $search_query Search query.
2479 *
2480 * @return array
2481 */
2482 public static function get_post_types( $search_query = null, $args = [] ) {
2483
2484 $args = wp_parse_args(
2485 $args,
2486 [
2487 'post_type' => 'any',
2488 'posts_per_page' => 20,
2489 'orderby' => 'ID',
2490 'order' => 'DESC',
2491 ]
2492 );
2493
2494 if ( 'archive' !== $args['post_type'] ) {
2495 if ( $search_query ) {
2496 $args['s'] = $search_query;
2497 }
2498 $posts = [];
2499 $query_results = get_posts( $args );
2500 foreach ( $query_results as $post ) {
2501 $posts[] = [
2502 'value' => $post->ID,
2503 'label' => $post->post_title,
2504 ];
2505 }
2506 if ( $search_query ) {
2507 if ( strpos( '-error 404', $search_query ) ) {
2508 $posts[] = [
2509 'value' => 'error',
2510 'label' => __( '404 Error', 'shopbuilder' ),
2511 ];
2512 }
2513 } else {
2514 $posts[] = [
2515 'value' => 'error',
2516 'label' => __( '404 Error', 'shopbuilder' ),
2517 ];
2518 }
2519 } else {
2520 $posts = self::get_registered_post_types( $search_query );
2521 }
2522
2523 return $posts;
2524 }
2525
2526 /**
2527 * Get all Elementor breakpoints.
2528 *
2529 * @return array
2530 */
2531 public static function get_elementor_breakpoints() {
2532 return ( new \Elementor\Core\Breakpoints\Manager() )->get_breakpoints_config();
2533 }
2534
2535 /**
2536 * Render view.
2537 *
2538 * @param string $viewName View name.
2539 * @param array $args View args.
2540 * @param boolean $return View return.
2541 * @return string|void
2542 */
2543 public static function renderView( $viewName, $args = [], $return = false ) {
2544 $viewName = str_replace( '.', '/', $viewName );
2545
2546 if ( ! empty( $args ) && is_array( $args ) ) {
2547 extract( $args );
2548 }
2549
2550 $view_file = rtsb()->plugin_path() . '/resources/' . $viewName . '.php';
2551
2552 if ( ! file_exists( $view_file ) ) {
2553 _doing_it_wrong( __FUNCTION__, sprintf( '<code>%s</code> does not exist.', esc_html( $view_file ) ), '1.7.0' );
2554
2555 return;
2556 }
2557
2558 if ( $return ) {
2559 ob_start();
2560 include $view_file;
2561
2562 return ob_get_clean();
2563 } else {
2564 include $view_file;
2565 }
2566 }
2567
2568 /**
2569 * Best selling product query.
2570 *
2571 * @param int $minimum_sale Minimum sale/
2572 * @param int $limit Total limit.
2573 *
2574 * @return array|mixed
2575 */
2576 public static function best_selling_products_ids( $minimum_sale = 1, $limit = 10 ) {
2577 $cache_key = 'rtsb_best_selling_products_' . $minimum_sale . '_' . $limit;
2578 // Check if the data is in the cache.
2579 if ( isset( self::$cache[ $cache_key ] ) ) {
2580 return self::$cache[ $cache_key ];
2581 }
2582 $cached_data = get_transient( $cache_key );
2583 if ( $cached_data ) {
2584 self::$cache[ $cache_key ] = $cached_data;
2585 return $cached_data;
2586 }
2587 global $wpdb;
2588 $sql = $wpdb->prepare(
2589 "
2590 SELECT ID
2591 FROM {$wpdb->posts} AS p
2592 LEFT JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id
2593 WHERE p.post_type = 'product'
2594 AND p.post_status = 'publish'
2595 AND pm.meta_key = 'total_sales'
2596 AND pm.meta_value >= %d
2597 ORDER BY pm.meta_value + 0 DESC
2598 LIMIT %d
2599 ",
2600 $minimum_sale,
2601 $limit
2602 );
2603 $best_selling = $wpdb->get_col( $sql );
2604 // Cache the result for future use.
2605 set_transient( $cache_key, $best_selling, DAY_IN_SECONDS );
2606 self::$cache[ $cache_key ] = $best_selling;
2607 return $best_selling;
2608 }
2609
2610 /**
2611 * @param null|Object $product Product Object.
2612 * @param int $days_threshold Date String.
2613 *
2614 * @return bool
2615 */
2616 public static function is_new_product( $product = null, $days_threshold = 30 ) {
2617 if ( is_null( $product ) ) {
2618 global $product;
2619 }
2620 if ( ! $product instanceof WC_Product ) {
2621 return false;
2622 }
2623
2624 $product_id = $product->get_id();
2625 $days_threshold = ! empty( $days_threshold ) ? $days_threshold : 30;
2626 $cache_key = 'is_new_product_' . $product_id . '_' . $days_threshold;
2627
2628 if ( isset( self::$cache[ $cache_key ] ) ) {
2629 return self::$cache[ $cache_key ];
2630 }
2631
2632 // Get the product publish date.
2633 $publish_timestamp = strtotime( $product->get_date_created()->date_i18n( 'Y-m-d H:i:s' ) );
2634
2635 // Calculate the difference in days.
2636 $days_difference = abs( time() - $publish_timestamp ) / ( 60 * 60 * 24 );
2637
2638 // Check if the product is considered new.
2639 $is_new = $days_difference <= $days_threshold;
2640
2641 // Cache the result for a day.
2642 self::$cache[ $cache_key ] = $is_new;
2643
2644 return $is_new;
2645 }
2646
2647 /**
2648 * Checks if a feature is disabled for guest users based on the provided option.
2649 *
2650 * @param string $option The option to retrieve from the item.
2651 * @param mixed $default The default value if the option is not found.
2652 *
2653 * @return bool
2654 */
2655 public static function is_guest_feature_disabled( $option, $default ) {
2656 $disabled = self::get_option( 'general', 'guest_user', $option, $default );
2657
2658 return ! is_user_logged_in() && $disabled;
2659 }
2660
2661 /**
2662 * Checks if a feature is disabled for guest users based on the provided option.
2663 *
2664 * @param string $option The option to retrieve from the item.
2665 * @param mixed $default The default value if the option is not found.
2666 *
2667 * @return bool
2668 */
2669 public static function woocommerce_output_all_notices() {
2670 if ( function_exists( 'wc_print_notices' ) ) :
2671 echo '<div class="rtsb-notice">';
2672 woocommerce_output_all_notices();
2673 echo '</div>';
2674 endif;
2675 }
2676 }
2677