PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 2.1.3
ShopBuilder – WooCommerce Builder For Elementor v2.1.3
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.3, at app/Helpers/Fns.php

2,622 lines 77.0 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
349 $product = wc_get_product( self::get_prepared_product_id() );
350 self::$cache[ $cache_key ] = $product;
351 do_action( 'rtsb_before_product_template_render' );
352 return $product;
353 }
354
355 /**
356 * Error function
357 *
358 * @param [type] $function function name.
359 * @param [type] $message message.
360 * @param [type] $version version.
361 *
362 * @return void
363 */
364 public static function doing_it_wrong( $function, $message, $version ) {
365 $message .= ' Backtrace: ' . wp_debug_backtrace_summary();
366 _doing_it_wrong( $function, $message, $version );
367 }
368
369 /**
370 * @return array
371 */
372 public static function get_pages() {
373 $pages = [];
374 $rawPages = get_pages();
375 if ( ! empty( $rawPages ) ) {
376 foreach ( $rawPages as $page ) {
377 $pages[ $page->ID ] = $page->post_title;
378 }
379 }
380
381 return $pages;
382 }
383
384 public static function get_section_items( $section_id ) {
385 if ( ! $section_id ) {
386 return [];
387 }
388
389 return DataModel::source()->get_option( $section_id, [] );
390 }
391
392 public static function get_options( $section_id, $item_id ) {
393 if ( ! $section_id || ! $item_id ) {
394 return [];
395 }
396 $sections = self::get_section_items( $section_id );
397
398 return isset( $sections[ $item_id ] ) ? $sections[ $item_id ] : [];
399 }
400
401 /**
402 * Get options value with default value if options doesn't exist.
403 *
404 * @param $group
405 * @param $option_key
406 * @param $default_value
407 *
408 * @return mixed|string
409 */
410 public static function get_options_by_default_val( $group, $option_key, $default_value = '' ) {
411
412 if ( ! $option_key || ! isset( $group[ $option_key ] ) ) {
413 return $default_value;
414 }
415
416 return $group[ $option_key ];
417 }
418
419 /**
420 * @param string $section_id
421 * @param string $item_id
422 * @param string $option_id
423 * @param null $default EXCEPT multi_checkbox you can provide default value if given option does not set any value
424 * @param null $type checkbox, multi_checkbox, number
425 *
426 * @return bool|int|mixed|null
427 */
428 public static function get_option( $section_id, $item_id, $option_id, $default = null, $type = null ) {
429 $options = self::get_options( $section_id, $item_id );
430
431 if ( $type === 'checkbox' ) {
432 if ( isset( $options[ $option_id ] ) ) {
433 return $options[ $option_id ] === 'on';
434 }
435
436 return $default;
437 } elseif ( $type === 'multi_checkbox' ) {
438 return isset( $options[ $option_id ] ) && is_array( $options[ $option_id ] ) && in_array( $default, $options[ $option_id ] );
439 } elseif ( $type === 'number' ) {
440 return isset( $options[ $option_id ] ) ? absint( $options[ $option_id ] ) : absint( $default );
441 }
442
443 return isset( $options[ $option_id ] ) && ! empty( $options[ $option_id ] ) ? $options[ $option_id ] : $default;
444 }
445
446
447 /**
448 * Create a page and store the ID in an option.
449 *
450 * @param mixed $slug Slug for the new page.
451 * @param array $options ['section_id', 'item_id', 'option_id']Option name to store the page's ID.
452 * @param string $page_title (default: '') Title for the new page.
453 * @param string $page_content (default: '') Content for the new page.
454 * @param int $post_parent (default: 0) Parent for the new page.
455 * @param string $post_status (default: publish) The post status of the new page.
456 *
457 * @return int page ID.
458 */
459 public static function create_page( $slug, $options = '', $page_title = '', $page_content = '', $post_parent = 0, $post_status = 'publish' ) {
460 global $wpdb;
461
462 $option_value = 0;
463 if ( ! empty( $options ) ) {
464 if ( is_array( $options ) ) {
465 $options = wp_parse_args(
466 $options,
467 [
468 'section_id' => '',
469 'item_id' => '',
470 'option_id' => '',
471 ]
472 );
473 $option_value = self::get_option( $options['section_id'], $options['item_id'], $options['option_id'], 0, 'number' );
474 } else {
475 $option_value = absint( get_option( $options ) );
476 }
477 }
478
479 if ( $option_value > 0 ) {
480 $page_object = get_post( $option_value );
481
482 if ( $page_object && 'page' === $page_object->post_type && ! in_array(
483 $page_object->post_status,
484 [
485 'pending',
486 'trash',
487 'future',
488 'auto-draft',
489 ],
490 true
491 ) ) {
492 // Valid page is already in place.
493 return $page_object->ID;
494 }
495 }
496
497 if ( strlen( $page_content ) > 0 ) {
498 // Search for an existing page with the specified page content (typically a shortcode).
499 $shortcode = str_replace( [ '<!-- wp:shortcode -->', '<!-- /wp:shortcode -->' ], '', $page_content );
500 $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}%" ) );
501 } else {
502 // Search for an existing page with the specified page slug.
503 $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 ) );
504 }
505
506 $valid_page_found = apply_filters( 'rtsb/core/create_page_id', $valid_page_found, $slug, $page_content, $options );
507
508 if ( $valid_page_found ) {
509 if ( is_array( $options ) ) {
510 if ( ! empty( $options['section_id'] ) && $options['item_id'] && $options['option_id'] ) {
511 $section_items = DataModel::source()->get_option( $options['section_id'], [] );
512 $section_items[ $options['item_id'] ][ $options['option_id'] ] = $valid_page_found;
513 DataModel::source()->set_option( $options['section_id'], $section_items );
514 }
515 } else {
516 if ( $options ) {
517 update_option( $options, $valid_page_found );
518 }
519 }
520
521 return $valid_page_found;
522 }
523
524 // Search for a matching valid trashed page.
525 if ( strlen( $page_content ) > 0 ) {
526 // Search for an existing page with the specified page content (typically a shortcode).
527 $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}%" ) );
528 } else {
529 // Search for an existing page with the specified page slug.
530 $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 ) );
531 }
532
533 if ( $trashed_page_found ) {
534 $page_id = $trashed_page_found;
535 $page_data = [
536 'ID' => $page_id,
537 'post_status' => $post_status,
538 ];
539 wp_update_post( $page_data );
540 } else {
541 $page_data = [
542 'post_status' => $post_status,
543 'post_type' => 'page',
544 'post_author' => 1,
545 'post_name' => $slug,
546 'post_title' => $page_title,
547 'post_content' => $page_content,
548 'post_parent' => $post_parent,
549 'comment_status' => 'closed',
550 ];
551 $page_id = wp_insert_post( $page_data );
552
553 do_action( 'rtsb/core/page_created', $page_id, $page_data );
554 }
555
556 if ( is_array( $options ) ) {
557 if ( ! empty( $options['section_id'] ) && $options['item_id'] && $options['option_id'] ) {
558 $section_items = DataModel::source()->get_option( $options['section_id'], [] );
559 $section_items[ $options['item_id'] ][ $options['option_id'] ] = $page_id;
560 DataModel::source()->set_option( $options['section_id'], $section_items );
561 }
562 } else {
563 if ( $options ) {
564 update_option( $options, $page_id );
565 }
566 }
567
568 return $page_id;
569 }
570
571 public static function get_kses_array() {
572 return [
573 'a' => [
574 'class' => [],
575 'href' => [],
576 'rel' => [],
577 'title' => [],
578 ],
579 'abbr' => [
580 'title' => [],
581 ],
582 'b' => [],
583 'blockquote' => [
584 'cite' => [],
585 ],
586 'cite' => [
587 'title' => [],
588 ],
589 'code' => [],
590 'del' => [
591 'datetime' => [],
592 'title' => [],
593 ],
594 'dd' => [],
595 'div' => [
596 'class' => [],
597 'title' => [],
598 'style' => [],
599 ],
600 'dl' => [],
601 'dt' => [],
602 'em' => [],
603 'h1' => [
604 'class' => [],
605 ],
606 'h2' => [
607 'class' => [],
608 ],
609 'h3' => [
610 'class' => [],
611 ],
612 'h4' => [
613 'class' => [],
614 ],
615 'h5' => [
616 'class' => [],
617 ],
618 'h6' => [
619 'class' => [],
620 ],
621 'i' => [
622 'class' => [],
623 ],
624 'img' => [
625 'alt' => [],
626 'class' => [],
627 'height' => [],
628 'src' => [],
629 'width' => [],
630 ],
631 'li' => [
632 'class' => [],
633 ],
634 'ol' => [
635 'class' => [],
636 ],
637 'p' => [
638 'class' => [],
639 ],
640 'q' => [
641 'cite' => [],
642 'title' => [],
643 ],
644 'span' => [
645 'class' => [],
646 'title' => [],
647 'style' => [],
648 ],
649 'iframe' => [
650 'width' => [],
651 'height' => [],
652 'scrolling' => [],
653 'frameborder' => [],
654 'allow' => [],
655 'src' => [],
656 ],
657 'strike' => [],
658 'br' => [],
659 'strong' => [],
660 'data-wow-duration' => [],
661 'data-wow-delay' => [],
662 'data-wallpaper-options' => [],
663 'data-stellar-background-ratio' => [],
664 'ul' => [
665 'class' => [],
666 ],
667 ];
668 }
669
670
671 /*
672 * Escape output of wishlist icon
673 *
674 * @param string $data Data to escape.
675 * @return string Escaped data
676 */
677 public static function print_icon( $data ) {
678 /**
679 * APPLY_FILTERS: rtsb/core/allowed_icon_html
680 *
681 * Filter the allowed HTML for the icons.
682 *
683 * @param array $allowed_icon_html Allowed HTML
684 *
685 * @return array
686 */
687 $allowed_icon_html = apply_filters(
688 'rtsb/core/allowed_icon_html',
689 [
690 'i' => [
691 'class' => true,
692 ],
693 'img' => [
694 'src' => true,
695 'alt' => true,
696 'width' => true,
697 'height' => true,
698 ],
699 'svg' => [
700 'class' => true,
701 'aria-hidden' => true,
702 'aria-labelledby' => true,
703 'role' => true,
704 'xmlns' => true,
705 'width' => true,
706 'height' => true,
707 'viewbox' => true,
708 'stroke' => true,
709 'fill' => true,
710 ],
711 'g' => [
712 'fill' => true,
713 ],
714 'title' => [
715 'title' => true,
716 ],
717 'path' => [
718 'd' => true,
719 'fill' => true,
720 'stroke' => true,
721 'stroke-width' => true,
722 'stroke-linecap' => true,
723 'stroke-linejoin' => true,
724 'fill-rule' => true,
725 'clip-rule' => true,
726 ],
727 ]
728 );
729
730 echo wp_kses( $data, $allowed_icon_html );
731 }
732
733 /**
734 * Prints HTMl.
735 *
736 * @param string $html HTML.
737 * @param bool $allHtml All HTML.
738 *
739 * @return void
740 */
741 public static function print_html( $html, $allHtml = false ) {
742 if ( ! $html ) {
743 return;
744 }
745 if ( $allHtml ) {
746 echo stripslashes_deep( $html ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
747 } else {
748 echo wp_kses_post( stripslashes_deep( $html ) );
749 }
750 }
751
752 /**
753 * Allowed HTML for wp_kses.
754 *
755 * @param string $level Tag level.
756 *
757 * @return mixed
758 */
759 public static function allowedHtml( $level = 'basic' ) {
760 $allowed_html = [];
761 // TODO:: Need Optimize.
762 switch ( $level ) {
763 case 'basic':
764 $allowed_html = [
765 'b' => [
766 'class' => [],
767 'id' => [],
768 ],
769 'i' => [
770 'class' => [],
771 'id' => [],
772 ],
773 'u' => [
774 'class' => [],
775 'id' => [],
776 ],
777 'br' => [
778 'class' => [],
779 'id' => [],
780 ],
781 'em' => [
782 'class' => [],
783 'id' => [],
784 ],
785 'span' => [
786 'class' => [],
787 'id' => [],
788 ],
789 'strong' => [
790 'class' => [],
791 'id' => [],
792 ],
793 'hr' => [
794 'class' => [],
795 'id' => [],
796 ],
797 'div' => [
798 'class' => [],
799 'id' => [],
800 ],
801 'a' => [
802 'href' => [],
803 'title' => [],
804 'class' => [],
805 'id' => [],
806 'target' => [],
807 ],
808 ];
809 break;
810
811 case 'advanced':
812 $allowed_html = [
813 'b' => [
814 'class' => [],
815 'id' => [],
816 ],
817 'i' => [
818 'class' => [],
819 'id' => [],
820 ],
821 'u' => [
822 'class' => [],
823 'id' => [],
824 ],
825 'br' => [
826 'class' => [],
827 'id' => [],
828 ],
829 'em' => [
830 'class' => [],
831 'id' => [],
832 ],
833 'span' => [
834 'class' => [],
835 'id' => [],
836 ],
837 'strong' => [
838 'class' => [],
839 'id' => [],
840 ],
841 'hr' => [
842 'class' => [],
843 'id' => [],
844 ],
845 'a' => [
846 'href' => [],
847 'title' => [],
848 'class' => [],
849 'id' => [],
850 'target' => [],
851 ],
852 'input' => [
853 'type' => [],
854 'name' => [],
855 'class' => [],
856 'value' => [],
857 ],
858 ];
859 break;
860
861 case 'image':
862 $allowed_html = [
863 'img' => [
864 'src' => [],
865 'data-src' => [],
866 'alt' => [],
867 'height' => [],
868 'width' => [],
869 'class' => [],
870 'id' => [],
871 'style' => [],
872 'srcset' => [],
873 'loading' => [],
874 'sizes' => [],
875 ],
876 'div' => [
877 'class' => [],
878 ],
879 ];
880 break;
881
882 case 'anchor':
883 $allowed_html = [
884 'a' => [
885 'href' => [],
886 'title' => [],
887 'class' => [],
888 'id' => [],
889 'style' => [],
890 ],
891 ];
892 break;
893
894 default:
895 // code...
896 break;
897 }
898
899 return $allowed_html;
900 }
901
902 /**
903 * Safe print a validated HTML tag.
904 *
905 * @param string $tag
906 */
907 public static function print_validated_html_tag( $tag ) {
908 $allowed_html_wrapper_tags = [
909 'a',
910 'article',
911 'aside',
912 'button',
913 'div',
914 'footer',
915 'h1',
916 'h2',
917 'h3',
918 'h4',
919 'h5',
920 'h6',
921 'header',
922 'main',
923 'nav',
924 'p',
925 'section',
926 'span',
927 ];
928
929 self::print_html( in_array( strtolower( $tag ), $allowed_html_wrapper_tags, true ) ? $tag : 'div' );
930 }
931
932 /**
933 * Insert Some array element
934 *
935 * @param [type] $key The elements will insert nearby this key.
936 * @param [type] $main_array Original array.
937 * @param [type] $insert_array some element will insert in original array.
938 * @param boolean $is_after array insert position base on the key.
939 *
940 * @return array
941 */
942 public static function insert_controls( $key, $main_array, $insert_array, $is_after = false ) {
943 $index = array_search( $key, array_keys( $main_array ), true );
944 if ( 'integer' === gettype( $index ) ) {
945 if ( $is_after ) {
946 $index++;
947 }
948 $main_array = array_merge(
949 array_slice( $main_array, 0, $index ),
950 $insert_array,
951 array_slice( $main_array, $index )
952 );
953 }
954
955 return $main_array;
956 }
957
958 /**
959 * Image Sizes
960 *
961 * @return array
962 */
963 public static function get_image_sizes() {
964 global $_wp_additional_image_sizes;
965
966 $sizes = [];
967
968 foreach ( get_intermediate_image_sizes() as $_size ) {
969 if ( in_array( $_size, [ 'thumbnail', 'medium', 'large' ], true ) ) {
970 $sizes[ $_size ]['width'] = get_option( "{$_size}_size_w" );
971 $sizes[ $_size ]['height'] = get_option( "{$_size}_size_h" );
972 $sizes[ $_size ]['crop'] = (bool) get_option( "{$_size}_crop" );
973 } elseif ( isset( $_wp_additional_image_sizes[ $_size ] ) ) {
974 $sizes[ $_size ] = [
975 'width' => $_wp_additional_image_sizes[ $_size ]['width'],
976 'height' => $_wp_additional_image_sizes[ $_size ]['height'],
977 'crop' => $_wp_additional_image_sizes[ $_size ]['crop'],
978 ];
979 }
980 }
981
982 $imgSize = [];
983
984 foreach ( $sizes as $key => $img ) {
985 $imgSize[ $key ] = ucfirst( $key ) . " ({$img['width']}*{$img['height']})";
986 }
987
988 $imgSize['full'] = esc_html__( 'Full size', 'shopbuilder' );
989 $imgSize['rtsb_custom'] = esc_html__( 'Custom image size', 'shopbuilder' );
990
991 return $imgSize;
992 }
993
994 /**
995 * Free Layouts
996 *
997 * @return array
998 */
999 public static function free_layouts() {
1000 $layouts = [
1001 'grid-layout1' => esc_html__( 'Grid Layout 1', 'shopbuilder' ),
1002 'grid-layout2' => esc_html__( 'Grid Layout 2', 'shopbuilder' ),
1003 'list-layout1' => esc_html__( 'List Layout 1', 'shopbuilder' ),
1004 'list-layout2' => esc_html__( 'List Layout 2', 'shopbuilder' ),
1005 'slider-layout1' => esc_html__( 'Slider Layout 1', 'shopbuilder' ),
1006 'slider-layout2' => esc_html__( 'Slider Layout 2', 'shopbuilder' ),
1007 'category-single-layout1' => esc_html__( 'Category Single Layout 1', 'shopbuilder' ),
1008 'category-layout1' => esc_html__( 'Category Layout 1', 'shopbuilder' ),
1009 'category-layout2' => esc_html__( 'Category Layout 2', 'shopbuilder' ),
1010 ];
1011
1012 return apply_filters( 'rtsb/elements/elementor/free_layouts', $layouts );
1013 }
1014
1015 /**
1016 * Get all terms by taxonomy
1017 *
1018 * @param string $taxonomy Taxonomy name.
1019 * @param bool $placeholder Placeholder..
1020 *
1021 * @return array
1022 */
1023 public static function get_all_terms( $taxonomy, $placeholder = false ) {
1024 $terms = [];
1025
1026 if ( empty( $taxonomy ) ) {
1027 return $terms;
1028 }
1029 $cache_key = 'rtsb_get_all_terms_by_tax_name_' . $taxonomy;
1030 if ( isset( self::$cache[ $cache_key ] ) ) {
1031 return self::$cache[ $cache_key ];
1032 }
1033
1034 $termList = get_terms( [ $taxonomy ], [ 'hide_empty' => 0 ] );
1035
1036 if ( is_array( $termList ) && ! empty( $termList ) && empty( $termList['errors'] ) ) {
1037 if ( $placeholder ) {
1038 $terms = [
1039 'all' => __( 'All Products', 'shopbuilder' ),
1040 ];
1041 }
1042
1043 foreach ( $termList as $term ) {
1044 $terms[ $term->term_id ] = esc_html( $term->name );
1045 }
1046 }
1047 self::$cache[ $cache_key ] = $terms;
1048 return $terms;
1049 }
1050
1051 /**
1052 * Get all terms by attributes
1053 *
1054 * @return array
1055 */
1056 public static function get_all_attributes() {
1057 $terms = [];
1058 $termList = [];
1059
1060 $attributes = wc_get_attribute_taxonomies();
1061
1062 if ( $attributes ) {
1063 foreach ( $attributes as $tax ) {
1064 if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) ) {
1065 $termList[ $tax->attribute_name ] = get_terms( wc_attribute_taxonomy_name( $tax->attribute_name ), 'orderby=name&hide_empty=0' );
1066 }
1067 }
1068 }
1069
1070 if ( ! empty( $termList ) && empty( $termList['errors'] ) && is_array( $termList ) ) {
1071 foreach ( $termList as $name => $atts ) {
1072 foreach ( $atts as $term ) {
1073 $terms[ $term->term_id ] = esc_html( ucwords( str_replace( '-', ' ', $name ) ) . ' - ' . $term->name );
1074 }
1075 }
1076 }
1077
1078 return $terms;
1079 }
1080
1081 /**
1082 * Get all attributes name
1083 *
1084 * @return array
1085 */
1086 public static function get_all_attributes_name() {
1087 $attributes_name = [];
1088
1089 $attributes = wc_get_attribute_taxonomies();
1090
1091 if ( $attributes ) {
1092 foreach ( $attributes as $tax ) {
1093 if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) ) {
1094 $attributes_name[ wc_attribute_taxonomy_name( $tax->attribute_name ) ] = ucwords( $tax->attribute_name );
1095 }
1096 }
1097 }
1098
1099 return $attributes_name;
1100 }
1101
1102 /**
1103 * Get User list
1104 *
1105 * @return array
1106 */
1107 public static function get_users() {
1108 $users = [];
1109 $u = get_users();
1110
1111 if ( ! empty( $u ) ) {
1112 foreach ( $u as $user ) {
1113 $users[ $user->ID ] = $user->display_name;
1114 }
1115 }
1116
1117 return $users;
1118 }
1119
1120 /**
1121 * Get Taxonomy List.
1122 *
1123 * @return array
1124 */
1125 public static function get_tax_list() {
1126 return apply_filters(
1127 'rtsb/elements/tax_list',
1128 [
1129 'product_cat' => esc_html__( 'Product Category', 'shopbuilder' ),
1130 ]
1131 );
1132 }
1133
1134 /**
1135 * Get Category Query List.
1136 *
1137 * @return array
1138 */
1139 public static function get_cat_list() {
1140 return [
1141 'all' => esc_html__( 'All Categories', 'shopbuilder' ),
1142 'specific_parent' => esc_html__( 'Sub-Categories by Parent', 'shopbuilder' ),
1143 'cat_ids' => esc_html__( 'Select by ID', 'shopbuilder' ),
1144 'selection' => esc_html__( 'Manual Selection', 'shopbuilder' ),
1145 ];
1146 }
1147
1148 /**
1149 * Get Term List.
1150 *
1151 * @param string $taxonomy Taxonomy.
1152 * @param bool $first_term First term.
1153 * @param bool $only_parents Only parent terms.
1154 * @param bool $return_slug Return with slug.
1155 *
1156 * @return int|array
1157 */
1158 public static function get_terms( $taxonomy, $first_term = false, $only_parents = false, $return_slug = false ) {
1159 if ( ! is_admin() ) {
1160 return [];
1161 }
1162
1163 // TODO:: Return Slug always true for all settings.
1164 $term_list = [];
1165 $args = [
1166 'taxonomy' => $taxonomy,
1167 'hide_empty' => false,
1168 ];
1169
1170 if ( $only_parents ) {
1171 $args['parent'] = 0;
1172 }
1173
1174 $terms = get_terms( $args );
1175
1176 if ( empty( $terms ) ) {
1177 return [ esc_html__( 'Nothing found', 'shopbuilder' ) ];
1178 }
1179
1180 foreach ( $terms as $term ) {
1181 if ( $return_slug ) {
1182 $term_list[ $term->slug ] = $term->name;
1183 } else {
1184 $term_list[ $term->term_id ] = $term->name;
1185 }
1186 }
1187
1188 if ( $first_term ) {
1189 return array_keys( $term_list )[0];
1190 } else {
1191 return $term_list;
1192 }
1193 }
1194
1195 /**
1196 * Get product rating.
1197 *
1198 * @param array $args Arguments.
1199 *
1200 * @return string|void
1201 */
1202 public static function get_product_rating_html( $args = [] ) {
1203 global $product;
1204
1205 $html = '';
1206 $rating_count = $product->get_rating_count();
1207 $average_rating = $product->get_average_rating();
1208
1209 if ( ! rtsb()->has_pro() || empty( $args ) ) {
1210 if ( ! $rating_count || empty( wc_get_rating_html( $average_rating, $rating_count ) ) ) {
1211 return $html;
1212 }
1213
1214 $html .= '<div class="product-rating">';
1215 $html .= wc_get_rating_html( $average_rating, $rating_count );
1216 $html .= ! empty( $html ) ? '<span class="rtsb-count">(' . $average_rating . ')</span>' : '';
1217 $html .= '</div>';
1218
1219 self::print_html( $html, true );
1220
1221 return;
1222 }
1223
1224 if ( empty( $rating_count ) && ! $args['show_empty_rating'] ) {
1225 return '';
1226 }
1227
1228 $preset = ! empty( $args['preset'] ) ? $args['preset'] : 'preset1';
1229 $average = $args['show_average_rating'] ? '<span class="rtsb-count">(' . $average_rating . ')</span>' : '';
1230 $count = '';
1231
1232 if ( $args['show_rating_count'] ) {
1233 $count .= '<div class="rtsb-count">';
1234 $count .= sprintf(
1235 /* translators: %s is the number of reviews */
1236 _n( '%s Review', '%s Reviews', $rating_count, 'shopbuilder' ),
1237 $rating_count
1238 );
1239 $count .= '</div>';
1240 }
1241
1242 if ( 'preset2' === $preset ) {
1243 $average = $args['show_average_rating'] ? '<div class="inner-wrapper"><span class="star-icon"></span><span class="average-rating">' . $average_rating . '</span></div>' : '';
1244 }
1245
1246 $html .= '<div class="product-rating ' . esc_attr( $preset ) . '">';
1247
1248 if ( 'preset1' === $preset ) {
1249 $html .= wc_get_rating_html( $average_rating, $rating_count );
1250 $html .= $average;
1251 $html .= $count;
1252 } elseif ( 'preset2' === $preset ) {
1253 $html .= $average;
1254 $html .= $count;
1255 }
1256
1257 $html .= '</div>';
1258
1259 self::print_html( $html, true );
1260 }
1261
1262 /**
1263 * Text truncation.
1264 *
1265 * @param string $text_to_truncate Text.
1266 * @param int $limit Limit.
1267 * @param string $after After text.
1268 *
1269 * @return string
1270 */
1271 public static function text_truncation( $text_to_truncate, $limit, $after = '&#8230;' ) {
1272 if ( empty( $limit ) ) {
1273 return $text_to_truncate;
1274 }
1275
1276 $limit++;
1277
1278 $text = '';
1279
1280 if ( mb_strlen( $text_to_truncate ) > $limit ) {
1281 $subex = mb_substr( wp_strip_all_tags( $text_to_truncate ), 0, $limit );
1282 $exwords = explode( ' ', $subex );
1283 $excut = - ( mb_strlen( $exwords[ count( $exwords ) - 1 ] ) );
1284
1285 if ( $excut < 0 ) {
1286 $text .= mb_substr( $subex, 0, $excut ) . $after;
1287 } else {
1288 $text .= $subex . $after;
1289 }
1290 } else {
1291 $text .= $text_to_truncate;
1292 }
1293
1294 return $text;
1295 }
1296
1297 /**
1298 * Promo Badge HTML
1299 *
1300 * @param string $text Text.
1301 * @param string $class Class.
1302 *
1303 * @return void
1304 */
1305 public static function get_badge_html( $text, $class = 'fill' ) {
1306 if ( empty( $text ) ) {
1307 return;
1308 }
1309 ob_start();
1310 ?>
1311
1312 <ul class="rtsb-promotion-list">
1313 <li class="rtsb-promotion-list-item">
1314 <span
1315 class="rtsb-tag-<?php echo ! empty( $class ) ? esc_attr( $class ) : ''; ?>"><?php echo esc_html( $text ); ?></span>
1316 </li>
1317 </ul>
1318
1319 <?php
1320 self::print_html( ob_get_clean() );
1321 }
1322
1323 /**
1324 * Categories HTML
1325 *
1326 * @param int $id Product ID.
1327 * @param string $class Custom class.
1328 *
1329 * @return void|string
1330 */
1331 public static function get_categories_list( $id, $class = 'rtsb-category-outline' ) {
1332 if ( empty( $id ) ) {
1333 return '';
1334 }
1335
1336 ob_start();
1337 ?>
1338
1339 <ul class="rtsb-category-list <?php echo esc_attr( $class ); ?>">
1340 <?php
1341 self::print_html(
1342 wc_get_product_category_list(
1343 $id,
1344 '</li><li class="rtsb-category-list-item">',
1345 '<li class="rtsb-category-list-item">',
1346 '</li>'
1347 )
1348 );
1349 ?>
1350 </ul>
1351
1352 <?php
1353 self::print_html( ob_get_clean() );
1354 }
1355
1356 /**
1357 * Get Featured Image HTML.
1358 *
1359 * @param string $type Image type.
1360 * @param int $post_id Post ID.
1361 * @param string $f_img_size Image size.
1362 * @param null $default_img_id Default image ID.
1363 * @param array $custom_img_size Custom image size.
1364 * @param bool $lazy Lazy load check.
1365 * @param bool $hover Hover image.
1366 * @param bool $gallery Gallery image.
1367 * @param bool $custom_image_id Custom category image ID.
1368 *
1369 * @return string|null
1370 */
1371 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 ) {
1372 $img_html = null;
1373 $attachment_id = null;
1374 $c_size = false;
1375 $hover_class = '';
1376 $post_title = '';
1377
1378 if ( 'rtsb_custom' === $f_img_size ) {
1379 $f_img_size = 'full';
1380 $c_size = true;
1381 }
1382
1383 if ( ! rtsb()->has_pro() ) {
1384 $gallery = false;
1385 }
1386
1387 if ( $hover ) {
1388 $a_id = $post_id;
1389 $hover_class = ' rtsb-img-hover';
1390 } elseif ( $gallery ) {
1391 $a_id = $post_id;
1392 } else {
1393 if ( 'product' === $type ) {
1394 $a_id = get_post_thumbnail_id( $post_id );
1395 $post_title = get_the_title( $post_id );
1396 } elseif ( 'category' === $type ) {
1397 $a_id = $custom_image_id ? $custom_image_id : get_term_meta( $post_id, 'thumbnail_id', true );
1398 $post_title = get_term( $post_id )->name;
1399 } else {
1400 $a_id = $default_img_id;
1401 }
1402 }
1403
1404 $img_alt = trim( wp_strip_all_tags( get_post_meta( $a_id, '_wp_attachment_image_alt', true ) ) );
1405 $alt_tag = ! empty( $img_alt ) ? $img_alt : wp_strip_all_tags( $post_title );
1406 $lazy_class = $lazy ? ' swiper-lazy' : '';
1407 $attr = [
1408 'class' => 'img-responsive rtsb-product-image' . $lazy_class . $hover_class,
1409 'alt' => $alt_tag,
1410 ];
1411
1412 if ( $a_id ) {
1413 $img_html = wp_get_attachment_image( $a_id, $f_img_size, false, $attr );
1414 $attachment_id = $a_id;
1415 }
1416
1417 if ( ! $img_html && $default_img_id ) {
1418 $img_html = wp_get_attachment_image( $default_img_id, $f_img_size, false, $attr );
1419 $attachment_id = $default_img_id;
1420 }
1421
1422 if ( $img_html && $c_size ) {
1423 preg_match( '@src="([^"]+)"@', $img_html, $match );
1424 $img_src = array_pop( $match );
1425 $w = ! empty( $custom_img_size['width'] ) ? absint( $custom_img_size['width'] ) : null;
1426 $h = ! empty( $custom_img_size['height'] ) ? absint( $custom_img_size['height'] ) : null;
1427 $c = ! empty( $custom_img_size['crop'] ) && 'soft' === $custom_img_size['crop'] ? false : true;
1428
1429 if ( $w && $h ) {
1430 $image = self::image_resize( $img_src, $w, $h, $c, false );
1431
1432 if ( ! empty( $image ) ) {
1433 [ $src, $width, $height ] = $image;
1434
1435 $hwstring = image_hwstring( $width, $height );
1436 $attachment = get_post( $attachment_id );
1437 $attr = apply_filters( 'wp_get_attachment_image_attributes', $attr, $attachment, $f_img_size );
1438
1439 if ( $lazy ) {
1440 $attr['data-src'] = $src;
1441 } else {
1442 $attr['src'] = $src;
1443 }
1444
1445 $attr = array_map( 'esc_attr', $attr );
1446 $img_html = rtrim( "<img $hwstring" );
1447
1448 foreach ( $attr as $name => $value ) {
1449 $img_html .= " $name=" . '"' . $value . '"';
1450 }
1451
1452 $img_html .= ' />';
1453 }
1454 }
1455 }
1456
1457 if ( ! $img_html ) {
1458 $hwstring = image_hwstring( 160, 160 );
1459 $attr = isset( $attr['src'] ) ? apply_filters( 'wp_get_attachment_image_attributes', $attr, false, $f_img_size ) : [];
1460 $attr['class'] = 'default-img';
1461 $attr['src'] = esc_url( rtsb()->get_assets_uri( 'images/demo.png' ) );
1462 $attr['alt'] = esc_html__( 'Default Image', 'shopbuilder' );
1463 $img_html = rtrim( "<img $hwstring" );
1464
1465 foreach ( $attr as $name => $value ) {
1466 $img_html .= " $name=" . '"' . $value . '"';
1467 }
1468
1469 $img_html .= ' />';
1470 }
1471
1472 if ( $lazy ) {
1473 $img_html = $img_html . '<div class="swiper-lazy-preloader swiper-lazy-preloader"></div>';
1474 }
1475
1476 return $img_html;
1477 }
1478
1479 /**
1480 * Call the Image resize model for resize function
1481 *
1482 * @param string $url URL.
1483 * @param int $width Width.
1484 * @param int $height Height.
1485 * @param string $crop Crop.
1486 * @param bool|true $single Single.
1487 * @param bool|false $upscale Upscale.
1488 *
1489 * @return array|bool|string
1490 */
1491 public static function image_resize( $url, $width = null, $height = null, $crop = null, $single = true, $upscale = false ) {
1492 $rtResize = new ReSizer();
1493
1494 return $rtResize->process( $url, $width, $height, $crop, $single, $upscale );
1495 }
1496
1497 /**
1498 * Get Product Image
1499 *
1500 * @param string $f_image Featured Image.
1501 * @param string $h_image Hover Image.
1502 *
1503 * @return void
1504 */
1505 public static function get_product_image( $f_image, $h_image = null ) {
1506 if ( empty( $f_image ) ) {
1507 return;
1508 }
1509
1510 echo wp_kses( $f_image, self::allowedHtml( 'image' ) );
1511
1512 if ( ! empty( $h_image ) ) {
1513 echo wp_kses( $h_image, self::allowedHtml( 'image' ) );
1514 }
1515 }
1516
1517 /**
1518 * Post Custom Field value.
1519 *
1520 * @param int $post_id Post id.
1521 * @param string $field_key Custom Field Key.
1522 * @param string $field_fallback FallBack text.
1523 *
1524 * @return string|void
1525 */
1526 public static function get_post_custom_field_value( $post_id, $field_key = '', $field_fallback = '' ) {
1527 if ( ! $post_id || ! $field_key ) {
1528 return;
1529 }
1530 $field_value = get_post_meta( $post_id, $field_key, true );
1531 if ( empty( $field_value ) ) {
1532 $field_value = ! empty( $field_fallback ) ? $field_fallback : $field_value;
1533 }
1534 $field_value = apply_filters( 'rtsb/get_post_custom_field_value/' . $field_key, $field_value, $field_key );
1535
1536 return sprintf( '<span class="rtsb-woo-custom-field">%s</span>', $field_value );
1537 }
1538
1539 /**
1540 * Elementor Icon
1541 *
1542 * @param array $control Elementor Control array.
1543 * @param string $class Custom class.
1544 * @param string $builder Builder name.
1545 *
1546 * @return string
1547 */
1548 public static function icons_manager( $control, $class = '', $builder = 'elementor' ): string {
1549 if ( empty( $control['value'] ) ) {
1550 return '';
1551 }
1552 if ( is_array( $control['value'] ) ) {
1553 $cache_key = 'icons_managet_' . str_replace( ' ', '', md5( serialize( $control['value'] ) ) );
1554 } else {
1555 $cache_key = 'icons_managet_' . str_replace( ' ', '', $control['value'] );
1556 }
1557 if ( isset( self::$cache[ $cache_key ] ) ) {
1558 return self::$cache[ $cache_key ];
1559 }
1560
1561 $attributes = [
1562 'aria-hidden' => 'true',
1563 ];
1564
1565 if ( ! empty( $class ) ) {
1566 $attributes['class'] = esc_attr( $class );
1567 }
1568
1569 ob_start();
1570
1571 if ( defined( 'ELEMENTOR_VERSION' ) && ! empty( $control ) && 'elementor' === $builder ) {
1572 Icons_Manager::render_icon( $control, $attributes );
1573 }
1574
1575 $icons = ob_get_clean();
1576 self::$cache[ $cache_key ] = $icons;
1577 return $icons;
1578 }
1579
1580 /**
1581 * Get product swatches.
1582 *
1583 * @param string $type Swatch type.
1584 *
1585 * @return void
1586 */
1587 public static function get_product_swatches( $type ) {
1588 ?>
1589 <div class="rtsb-swatches <?php echo esc_attr( $type ); ?>-layout">
1590 <?php
1591 do_action( 'rtwpvs_show_archive_variation' );
1592 ?>
1593 </div>
1594 <?php
1595 }
1596
1597 /**
1598 * Get sale badge
1599 *
1600 * @param string $type Badge type.
1601 * @param string $text Badge text.
1602 * @param string $out_of_stock_text Out of stock text.
1603 *
1604 * @return string
1605 */
1606 public static function get_sale_badge( $type, $text, $out_of_stock_text ) {
1607 global $product;
1608
1609 if ( ! $product->is_in_stock() ) {
1610 return $out_of_stock_text;
1611 }
1612
1613 if ( ! $product->is_on_sale() ) {
1614 return '';
1615 }
1616
1617 $badge_text = '';
1618 $percentage = self::calculate_sale_percentage( $product );
1619
1620 if ( $percentage > 0 ) {
1621 $badge_text = '-' . round( $percentage ) . '%';
1622 }
1623
1624 if ( 'text' === $type ) {
1625 $badge_text = $text;
1626 }
1627
1628 return $badge_text;
1629 }
1630
1631 /**
1632 * Get sale badge
1633 *
1634 * @param object $product Product Object.
1635 * @param string $type Badge type.
1636 * @param string $text Badge text.
1637 * @param string $out_of_stock_text Out of stock text.
1638 *
1639 * @return string
1640 */
1641 public static function get_promo_badge( $product, $type, $text, $out_of_stock_text ) {
1642 $disable_badges = self::get_option( 'general', 'guest_user', 'hide_badges', '' );
1643 $badges_visibility = rtsb()->has_pro() && ! is_user_logged_in() && $disable_badges;
1644
1645 if ( $badges_visibility ) {
1646 return '';
1647 }
1648
1649 if ( is_null( $product ) ) {
1650 global $product;
1651 }
1652
1653 if ( ! $product instanceof WC_Product ) {
1654 return '';
1655 }
1656
1657 if ( ! $product->is_in_stock() ) {
1658 return $out_of_stock_text;
1659 }
1660
1661 if ( ! $product->is_on_sale() ) {
1662 return '';
1663 }
1664
1665 $badge_text = '';
1666 $percentage = self::calculate_sale_percentage( $product );
1667
1668 if ( $percentage > 0 ) {
1669 $badge_text = '-' . round( $percentage ) . '%';
1670 }
1671
1672 if ( 'text' === $type ) {
1673 $badge_text = $text;
1674 }
1675
1676 return $badge_text;
1677 }
1678
1679 /**
1680 * Calculate Sale Percentage
1681 *
1682 * @param object $product Product object.
1683 *
1684 * @return float|int|string
1685 */
1686 public static function calculate_sale_percentage( $product = null ) {
1687 if ( is_null( $product ) ) {
1688 global $product;
1689 }
1690
1691 if ( ! $product instanceof WC_Product ) {
1692 return '';
1693 }
1694
1695 $percentage = null;
1696 $max_percentage = '';
1697
1698 if ( $product->is_type( 'simple' ) ) {
1699 $max_percentage = ( ( $product->get_regular_price() - $product->get_sale_price() ) / $product->get_regular_price() ) * 100;
1700 } elseif ( $product->is_type( 'variable' ) ) {
1701 $max_percentage = 0;
1702
1703 foreach ( $product->get_children() as $child_id ) {
1704
1705 $variation = wc_get_product( $child_id );
1706
1707 $price = $variation->get_regular_price();
1708 $sale = $variation->get_sale_price();
1709
1710 if ( 0 !== $price && ! empty( $sale ) ) {
1711 $percentage = ( $price - $sale ) / $price * 100;
1712 }
1713
1714 if ( $percentage > $max_percentage ) {
1715 $max_percentage = $percentage;
1716 }
1717 }
1718 }
1719
1720 if ( $max_percentage > 0 ) {
1721 return round( $max_percentage );
1722 }
1723
1724 return 0;
1725 }
1726
1727 /**
1728 * Pagination
1729 *
1730 * @param string $pages Pages.
1731 * @param integer $range Range.
1732 * @param boolean $ajax Ajax.
1733 *
1734 * @return string
1735 */
1736 public static function custom_pagination( $pages = '', $range = 4, $ajax = false ) {
1737 $html = null;
1738 $showitems = ( $range * 2 ) + 1;
1739
1740 global $paged;
1741
1742 if ( is_front_page() ) {
1743 $paged = ( get_query_var( 'page' ) ) ? get_query_var( 'page' ) : 1;
1744 } else {
1745 $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
1746 }
1747
1748 if ( empty( $paged ) ) {
1749 $paged = 1;
1750 }
1751
1752 if ( '' === $pages ) {
1753 global $wp_query;
1754
1755 $pages = $wp_query->max_num_pages;
1756
1757 if ( ! $pages ) {
1758 $pages = 1;
1759 }
1760 }
1761
1762 $ajaxClass = null;
1763 $dataAttr = null;
1764
1765 if ( $ajax ) {
1766 $ajaxClass = ' rtsb-pagination-ajax';
1767 $dataAttr = "data-paged='1'";
1768 }
1769
1770 if ( 1 !== $pages ) {
1771 $html .= '<div class="rtsb-pagination' . $ajaxClass . '" ' . $dataAttr . '>';
1772 $html .= '<ul class="pagination-list">';
1773
1774 if ( $paged > 2 && $paged > $range + 1 && $showitems < $pages ) {
1775 $html .= "<li><a data-paged='1' href='" . get_pagenum_link( 1 ) . "' aria-label='First'>&laquo;</a></li>";
1776 }
1777
1778 if ( $paged > 1 && $showitems < $pages ) {
1779 $p = $paged - 1;
1780 $html .= "<li><a data-paged='{$p}' href='" . get_pagenum_link( $p ) . "' aria-label='Previous'>&lsaquo;</a></li>";
1781 }
1782
1783 for ( $i = 1; $i <= $pages; $i++ ) {
1784 if ( 1 != $pages && ( ! ( $i >= $paged + $range + 1 || $i <= $paged - $range - 1 ) || $pages <= $showitems ) ) {
1785 $html .= ( $paged == $i ) ? '<li class="active"><span>' . $i . '</span></li>' : "<li><a data-paged='{$i}' href='" . get_pagenum_link( $i ) . "'>" . $i . '</a></li>';
1786 }
1787 }
1788
1789 if ( $paged < $pages && $showitems < $pages ) {
1790 $p = $paged + 1;
1791 $html .= "<li><a data-paged='{$p}' href=\"" . get_pagenum_link( $paged + 1 ) . "\" aria-label='Next'>&rsaquo;</a></li>";
1792 }
1793
1794 if ( $paged < $pages - 1 && $paged + $range - 1 < $pages && $showitems < $pages ) {
1795 $html .= "<li><a data-paged='{$pages}' href='" . get_pagenum_link( $pages ) . "' aria-label='Last'>&raquo;</a></li>";
1796 }
1797
1798 $html .= '</ul>';
1799 $html .= '</div>';
1800 }
1801
1802 return $html;
1803 }
1804
1805 /**
1806 * Action Buttons HTMl
1807 *
1808 * @param array $items Items.
1809 * @param array $ajax_cart Ajax cart HTML.
1810 * @param string $preset Button preset.
1811 * @param array $position Position.
1812 * @param string $placement Placement.
1813 *
1814 * @return void|string
1815 */
1816 public static function get_formatted_action_buttons( $items, $ajax_cart = '', $preset = 'preset1', $position = 'above', $placement = 'top' ) {
1817 if ( empty( $items ) ) {
1818 return;
1819 }
1820
1821 $html = '';
1822 $class = '';
1823 $args = [ $items, $ajax_cart, $preset, $position, $placement ];
1824
1825 if ( ( 'top' === $placement && 'after' === $position ) || ( 'bottom' === $placement && 'above' === $position ) ) {
1826 return apply_filters( 'rtsb/elements/elementor/formatted_action_buttons', $html, $args );
1827 }
1828
1829 if ( 'preset2' === $preset ) {
1830 $class = 'rtsb-action-buttons-vertical vertical-delay-effect ' . $preset;
1831 } elseif ( 'preset4' === $preset ) {
1832 $class = 'rtsb-action-buttons-vertical rtsb-action-buttons-vertical-left vertical-delay-effect ' . $preset;
1833 } elseif ( 'preset1' === $preset || 'preset3' === $preset ) {
1834 $class = 'rtsb-action-buttons-cart-box-width-auto horizontal-floating-btn ' . $preset;
1835 }
1836
1837 if ( 'after' === $position && 'preset1' === $preset ) {
1838 $class .= ' after-content';
1839 }
1840
1841 if ( 'preset3' === $preset ) {
1842 $html .= '<div class="rtsb-action-buttons top-part ' . esc_attr( $preset ) . '">';
1843 $html .= '<ul class="rtsb-action-button-list">';
1844
1845 ob_start();
1846 /**
1847 * Additional formatted action buttons hook.
1848 */
1849 do_action( 'rtsb/elements/elementor/additional_action_buttons', $items );
1850 $html .= ob_get_clean();
1851
1852 $html .= self::get_action_button_by_type( $items, 'wishlist' );
1853 $html .= self::get_action_button_by_type( $items, 'compare' );
1854 $html .= self::get_action_button_by_type( $items, 'quick_view' );
1855 $html .= '</ul>';
1856 $html .= '</div>';
1857 $html .= '<div class="rtsb-action-buttons bottom-part ' . esc_attr( $preset ) . '">';
1858 $html .= '<ul class="rtsb-action-button-list">';
1859 $html .= self::get_action_button_by_type( $items, 'add_to_cart', $ajax_cart );
1860 $html .= '</ul>';
1861 $html .= '</div>';
1862 } elseif ( 'preset1' === $preset || 'preset2' === $preset || 'preset4' === $preset ) {
1863 $html .= '<div class="rtsb-action-buttons ' . esc_attr( $class ) . '">';
1864 $html .= '<ul class="rtsb-action-button-list">';
1865 $html .= self::get_action_button_by_type( $items, 'add_to_cart', $ajax_cart );
1866
1867 ob_start();
1868 /**
1869 * Additional formatted action buttons hook.
1870 */
1871 do_action( 'rtsb/elements/elementor/additional_action_buttons', $items );
1872 $html .= ob_get_clean();
1873
1874 $html .= self::get_action_button_by_type( $items, 'wishlist' );
1875 $html .= self::get_action_button_by_type( $items, 'compare' );
1876 $html .= self::get_action_button_by_type( $items, 'quick_view' );
1877 $html .= '</ul>';
1878 $html .= '</div>';
1879 }
1880
1881 return apply_filters( 'rtsb/elements/elementor/formatted_action_buttons', $html, $args );
1882 }
1883
1884 /**
1885 * Get Action Button HTML
1886 *
1887 * @param array $items Items.
1888 * @param string $type Button type.
1889 * @param string $cart_html Ajax cart HTML.
1890 * @param string $wrapper Wrapper tag.
1891 *
1892 * @return void|string
1893 */
1894 public static function get_action_button_by_type( $items, $type, $cart_html = '', $wrapper = 'li' ) {
1895 if ( ! in_array( $type, $items, true ) ) {
1896 return;
1897 }
1898
1899 $html = '';
1900 $class = 'rtsb-action-button-item';
1901
1902 if ( 'add_to_cart' === $type ) {
1903 $class .= ' rtsb-cart' . ( empty( $cart_html ) ? esc_attr( ' no-cart-button' ) : '' );
1904 } else {
1905 $class .= ' rtsb-' . esc_attr( str_replace( '_', '-', $type ) );
1906 }
1907
1908 $html .= '<' . esc_attr( $wrapper ) . ' class="' . esc_attr( $class ) . '">';
1909
1910 if ( ( 'add_to_cart' === $type ) && ( ! empty( $cart_html ) ) ) {
1911 $html .= $cart_html;
1912 } else {
1913 $html .= shortcode_exists( 'rtsb_' . $type . '_button' ) ? do_shortcode( '[rtsb_' . $type . '_button]' ) : null;
1914 }
1915
1916 $html .= '</' . esc_attr( $wrapper ) . '>';
1917
1918 return apply_filters( 'rtsb/elements/elementor/get_action_button_by_type', $html );
1919 }
1920
1921 /**
1922 * Social Share Platforms.
1923 *
1924 * @return mixed|null
1925 */
1926 public static function social_share_platforms_list() {
1927 return apply_filters(
1928 'rtsb/settings/social_share/platforms',
1929 [
1930 [
1931 'value' => 'facebook',
1932 'label' => esc_html__( 'Facebook', 'shopbuilder' ),
1933 ],
1934 [
1935 'value' => 'twitter',
1936 'label' => esc_html__( 'Twitter', 'shopbuilder' ),
1937 ],
1938 [
1939 'value' => 'linkedin',
1940 'label' => esc_html__( 'Linkedin', 'shopbuilder' ),
1941 ],
1942 [
1943 'value' => 'pinterest',
1944 'label' => esc_html__( 'Pinterest', 'shopbuilder' ),
1945 ],
1946 [
1947 'value' => 'skype',
1948 'label' => esc_html__( 'Skype', 'shopbuilder' ),
1949 ],
1950 [
1951 'value' => 'whatsapp',
1952 'label' => esc_html__( 'Whatsapp', 'shopbuilder' ),
1953 ],
1954 [
1955 'value' => 'reddit',
1956 'label' => esc_html__( 'Reddit', 'shopbuilder' ),
1957 ],
1958 [
1959 'value' => 'telegram',
1960 'label' => esc_html__( 'Telegram', 'shopbuilder' ),
1961 ],
1962 ]
1963 );
1964 }
1965
1966 /**
1967 * Get Social Share link HTML.
1968 *
1969 * @param int $id Post ID.
1970 * @param array $types Preset type.
1971 * @param string $preset Style type.
1972 * @param boolean $show_icon Show icon.
1973 * @param boolean $show_text Show text.
1974 *
1975 * @return string
1976 */
1977 public static function get_social_share_html( int $id, array $types, string $preset = 'default', $show_icon = true, $show_text = true ) {
1978 $attr = [ 'postid' => $id ];
1979 $output = '';
1980
1981 if ( empty( $types ) ) {
1982 return $output;
1983 }
1984
1985 foreach ( $types as $type ) {
1986 $link = [];
1987 $link['type'] = $type['share_items'];
1988 $link['class'] = '';
1989 $link['img'] = apply_filters( 'rtsb/elements/share/default_img', '', $id, $link );
1990
1991 if ( 'site' === $id ) {
1992 $link['url'] = home_url();
1993 $link['title'] = wp_strip_all_tags( get_bloginfo( 'name' ) );
1994 } elseif ( 0 === strpos( $id, 'http' ) ) {
1995 $link['url'] = $id;
1996 $link['title'] = '';
1997 } else {
1998 $link['url'] = get_permalink( $id );
1999 $link['title'] = wp_strip_all_tags( get_the_title( $id ) );
2000
2001 if ( has_post_thumbnail( $id ) ) {
2002 $link['img'] = wp_get_attachment_image_url( get_post_thumbnail_id( $id ), 'full' );
2003 }
2004
2005 $link['img'] = apply_filters( 'rtsb/elements/share/single_img', $link['img'], $id, $link );
2006 }
2007
2008 $link['url'] = apply_filters( 'rtsb/elements/share/url', $link['url'], $link );
2009
2010 switch ( $type['share_items'] ) {
2011 case 'facebook':
2012 $link['link'] = esc_url( 'https://www.facebook.com/sharer/sharer.php?u=' . $link['url'] . '&display=popup&ref=plugin&src=share_button' );
2013 $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>';
2014 $link['attr_title'] = esc_html__( 'Share on Facebook', 'shopbuilder' );
2015 $link['social_network'] = 'Facebook';
2016 $link['social_action'] = 'Share';
2017 break;
2018 case 'twitter':
2019 $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'] );
2020 $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>';
2021 $link['attr_title'] = esc_html__( 'Share on Twitter', 'shopbuilder' );
2022 $link['social_network'] = 'Twitter';
2023 $link['social_action'] = 'Tweet';
2024 break;
2025 case 'pinterest':
2026 $link['link'] = esc_url( 'https://pinterest.com/pin/create/button/?url=' . $link['url'] . '&media=' . $link['img'] . '&description=' . $link['title'] );
2027 $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>';
2028 $link['attr_title'] = esc_html__( 'Share on Pinterest', 'shopbuilder' );
2029 $link['social_network'] = 'Pinterest';
2030 $link['social_action'] = 'Pin';
2031 break;
2032 case 'linkedin':
2033 $link['link'] = esc_url( 'https://www.linkedin.com/shareArticle?url=' . $link['url'] . '&title=' . $link['title'] );
2034 $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>';
2035 $link['attr_title'] = esc_html__( 'Share on LinkedIn', 'shopbuilder' );
2036 $link['social_network'] = 'LinkedIn';
2037 $link['social_action'] = 'Share';
2038 break;
2039 case 'skype':
2040 $link['link'] = esc_url( 'https://web.skype.com/share?url=' . $link['url'] );
2041 $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>';
2042 $link['attr_title'] = esc_html__( 'Share on Skype', 'shopbuilder' );
2043 $link['social_network'] = 'Skype';
2044 $link['social_action'] = 'Skype';
2045 break;
2046 case 'whatsapp':
2047 $link['link'] = esc_url( 'https://wa.me/?text=' . $link['title'] . ' ' . $link['url'] );
2048 $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>';
2049 $link['attr_title'] = esc_html__( 'Share on Whatsapp', 'shopbuilder' );
2050 $link['social_network'] = 'Whatsapp';
2051 $link['social_action'] = 'Share';
2052 break;
2053 case 'reddit':
2054 $link['link'] = esc_url( 'https://reddit.com/submit?url=' . $link['url'] . '&title=' . $link['title'] );
2055 $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>';
2056 $link['attr_title'] = esc_html__( 'Share on Reddit', 'shopbuilder' );
2057 $link['social_network'] = 'Reddit';
2058 $link['social_action'] = 'Share';
2059 break;
2060 case 'telegram':
2061 $link['link'] = esc_url( 'https://telegram.me/share/url?text=' . $link['title'] . '&url=' . $link['url'] );
2062 $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>';
2063 $link['attr_title'] = esc_html__( 'Share on Telegram', 'shopbuilder' );
2064 $link['social_network'] = 'Telegram';
2065 $link['social_action'] = 'Share';
2066 break;
2067 }
2068
2069 $link['label'] = $type['share_text'];
2070 $link['target'] = '_blank';
2071 $link['rel'] = 'nofollow noopener noreferrer';
2072
2073 $data = '';
2074 $link = apply_filters( 'rtsb/elements/share/share_link', $link, $id, $preset );
2075 $icon = apply_filters( 'rtsb/elements/share/share_icon', $link['icon'], $preset );
2076 $target = ! empty( $link['target'] ) ? ' target="' . esc_attr( $link['target'] ) . '" ' : '';
2077 $rel = ! empty( $link['rel'] ) ? ' rel="' . esc_attr( $link['rel'] ) . '" ' : '';
2078 $attr_title = ! empty( $link['attr_title'] ) ? ' title="' . esc_attr( $link['attr_title'] ) . '" ' : '';
2079 $elements = [];
2080
2081 // Add classes.
2082 $css_classes = [
2083 'rtsb-share-btn',
2084 sanitize_html_class( $link['type'] ),
2085 ];
2086 $css_classes = array_merge( $css_classes, explode( ' ', $link['class'] ) );
2087 $css_classes = array_map( 'sanitize_html_class', $css_classes );
2088 $css_classes = implode( ' ', array_filter( $css_classes ) );
2089
2090 unset( $attr['pin-do'], $attr['action'] );
2091
2092 if ( 'pinterest' === $type['share_items'] ) {
2093 $attr['pin-do'] = 'none';
2094 }
2095
2096 if ( 'whatsapp' === $type['share_items'] ) {
2097 $attr['action'] = 'share/whatsapp/share';
2098 }
2099
2100 $attr = apply_filters( 'rtsb/elements/share/link_data', $attr, $link, $id );
2101
2102 if ( ! empty( $attr ) ) {
2103 foreach ( $attr as $key => $val ) {
2104 $data .= ' data-' . sanitize_html_class( $key ) . '="' . esc_attr( $val ) . '"';
2105 }
2106 }
2107
2108 $additional_attr = apply_filters( 'rtsb/elements/share/additional_attr', [], $link, $id, $preset );
2109
2110 if ( ! empty( $additional_attr ) ) {
2111 $attr_output = join( ' ', $additional_attr );
2112
2113 if ( ! empty( $data ) ) {
2114 $attr_output = ' ' . $attr_output;
2115 }
2116
2117 $data .= $attr_output;
2118 }
2119
2120 $elements['wrapper_start'] = sprintf(
2121 '<li class="rtsb-share-item"><a href="%s"%s%s%s class="%s"%s>',
2122 ! empty( $link['link'] ) ? esc_attr( $link['link'] ) : '',
2123 $attr_title,
2124 $target,
2125 $rel,
2126 $css_classes,
2127 $data
2128 );
2129 $elements['wrapper_end'] = '</a></li>';
2130
2131 $elements['icon'] = $show_icon ? '<span class="rtsb-share-icon">' . ( ! empty( $icon ) ? $icon : null ) . '</span>' : null;
2132 $elements['label'] = $show_text && ! empty( $link['label'] ) ? '<span class="rtsb-share-label">' . $link['label'] . '</span>' : null;
2133 $elements['icon_label'] = '<span class="rtsb-share-icon-label">' . $elements['icon'] . $elements['label'] . '</span>';
2134 $elements = apply_filters( 'rtsb/elements/share/output_elements', $elements, $link, $id );
2135
2136 $output .= $elements['wrapper_start'] . $elements['icon_label'] . $elements['wrapper_end'];
2137 }
2138
2139 return apply_filters( 'rtsb/elements/share/list_output', $output );
2140 }
2141
2142 /**
2143 * Social Share Platforms.
2144 *
2145 * @return mixed|null
2146 */
2147 public static function is_module_active( $module ) {
2148 $modulelist = ModuleList::instance()->get_data();
2149 if ( ! empty( $modulelist[ $module ]['active'] ) ) {
2150 return true;
2151 }
2152 }
2153
2154
2155 /***
2156 * Save Settings data
2157 *
2158 * @param $section_id
2159 * @param $block_id
2160 * @param $rawOptions
2161 *
2162 * @return array
2163 */
2164 public static function set_options( $section_id = '', $block_id = '', $rawOptions = [] ) {
2165 $section_id = ! empty( $section_id ) ? sanitize_text_field( wp_unslash( $section_id ) ) : '';
2166 $block_id = ! empty( $block_id ) ? sanitize_text_field( wp_unslash( $block_id ) ) : '';
2167 $rawOptions = ! empty( $rawOptions ) ? $rawOptions : [];
2168
2169 $results = [
2170 'status' => true,
2171 'message' => '',
2172 ];
2173 if ( ! $section_id || ! $block_id ) {
2174 $results['status'] = false;
2175 $results['message'] = esc_html__( 'Section , block or options may be empty', 'shopbuilder' );
2176
2177 return $results;
2178 }
2179 $sections = Settings::instance()->get_sections();
2180 if ( empty( $sections[ $section_id ] ) || empty( $sections[ $section_id ]['list'][ $block_id ] ) ) {
2181 $results['status'] = false;
2182 $results['message'] = esc_html__( 'No section or block found with given data', 'shopbuilder' );
2183
2184 return $results;
2185 }
2186
2187 $options = DataModel::source()->get_option( $section_id, [] );
2188 $changed = false;
2189 $fields = [];
2190 if ( isset( $sections[ $section_id ]['list'][ $block_id ]['fields'] ) && ! empty( $sections[ $section_id ]['list'][ $block_id ]['fields'] ) ) {
2191 $fields = $sections[ $section_id ]['list'][ $block_id ]['fields'];
2192 }
2193
2194 if ( empty( $fields ) ) {
2195 if ( isset( $rawOptions['active'] ) ) {
2196 $changed = true;
2197 $options[ $block_id ]['active'] = 'on' === $rawOptions['active'] ? 'on' : '';
2198 }
2199 } else {
2200 foreach ( $rawOptions as $raw_option_key => $raw_value ) {
2201 if ( $raw_option_key === 'active' ) {
2202 $changed = true;
2203 $options[ $block_id ]['active'] = $sections[ $section_id ]['list'][ $block_id ]['active'] = 'on' === $raw_value ? 'on' : '';
2204 } else {
2205 if ( isset( $fields[ $raw_option_key ] ) ) {
2206 $field = $fields[ $raw_option_key ];
2207 if ( $field['type'] === 'switch' ) {
2208 $value = 'on' === $raw_value ? 'on' : '';
2209 } elseif ( 'repeaters' === $field['type'] ) {
2210 $value = stripslashes_deep( $raw_value );
2211 } else {
2212 if ( ! empty( $field['multiple'] ) || in_array( $field['type'], [ 'checkbox', 'search_and_multi_select' ] ) ) {
2213
2214 if ( isset( $raw_value ) && is_array( $raw_value ) ) {
2215 if ( ! empty( $field['sanitize_fn'] ) && is_callable( $field['sanitize_fn'] ) ) {
2216 $value = array_map( $field['sanitize_fn'], $raw_value );
2217 } else {
2218 $value = array_map( 'sanitize_text_field', $raw_value );
2219 }
2220 } else {
2221 $value = [];
2222 }
2223 } else {
2224 if ( ! empty( $field['sanitize_fn'] ) && is_callable( $field['sanitize_fn'] ) ) {
2225 $value = $field['sanitize_fn']( $raw_value );
2226 } else {
2227 $value = sanitize_text_field( $raw_value );
2228 }
2229 }
2230 }
2231 $options[ $block_id ][ $raw_option_key ] = $sections[ $section_id ]['list'][ $block_id ]['fields'][ $raw_option_key ]['value'] = $value ?? null;
2232 $changed = true;
2233 }
2234 }
2235 }
2236 }
2237 if ( ! $changed ) {
2238 $results['status'] = false;
2239 $results['message'] = esc_html__( 'No changes found for update', 'shopbuilder' );
2240
2241 return $results;
2242 }
2243
2244 DataModel::source()->set_option( $section_id, $options );
2245
2246 $results['status'] = true;
2247 $results['message'] = esc_html__( 'Successfully Saved', 'shopbuilder' );
2248 $results['sections'] = $sections;
2249
2250 return $results;
2251 }
2252
2253 /***
2254 * @param $meta_key
2255 * @param $meta_value
2256 *
2257 * @return mixed|void
2258 *
2259 *
2260 * public static function get_post_id_by_meta_key_and_value( $meta_key, $meta_value ) {
2261 * if( ! $meta_key || ! $meta_value ){
2262 * return;
2263 * }
2264 * global $wpdb;
2265 * $prepare_guery = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '%s' and meta_value = '%d'", $meta_key, $meta_value );
2266 * $the_products = $wpdb->get_col( $prepare_guery );
2267 * if( count( $the_products ) > 0 ){
2268 * return $the_products[0];
2269 * }
2270 * return;
2271 * }
2272 */
2273
2274 public static function count_products_by_taxonomies( $terms, $taxonomy = 'product_cat' ) {
2275 if ( empty( $terms ) || ! is_array( $terms ) ) {
2276 return;
2277 }
2278
2279 $args = [
2280 'limit' => -1,
2281 'return' => 'ids',
2282 ];
2283
2284 if ( 'product_cat' === $taxonomy ) {
2285 $args['product_category_id'] = $terms;
2286 } else {
2287 $args['product_tag_id'] = $terms;
2288 }
2289
2290 $query = new WC_Product_Query( $args );
2291
2292 return ! empty( $query->get_products() ) ? count( $query->get_products() ) : 0;
2293 }
2294
2295 /**
2296 * Check if product filters widget has ajax.
2297 *
2298 * @param string $page Page name.
2299 *
2300 * @return bool
2301 */
2302 public static function product_filters_has_ajax( $page ) {
2303 if ( empty( $page ) ) {
2304 return false;
2305 }
2306
2307 if ( 'page' === get_post_type() ) {
2308 return false;
2309 }
2310
2311 $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page );
2312 $cache_key = 'product_filters_has_ajax_' . $id;
2313 if ( isset( self::$cache[ $cache_key ] ) ) {
2314 return self::$cache[ $cache_key ];
2315 }
2316 $elmap = ElementorDataMap::instance();
2317 $ajax = [];
2318
2319 foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) {
2320 $ajax[] = isset( $data['settings']['ajax_mode'] ) ? false : true;
2321 }
2322 self::$cache[ $cache_key ] = ! empty( $ajax[0] );
2323 return ! empty( $ajax[0] );
2324 }
2325
2326 /**
2327 * Check if product has applied filter.
2328 *
2329 * @param string $page Page name.
2330 *
2331 * @return bool
2332 */
2333 public static function product_has_applied_filters( $page ) {
2334 if ( empty( $page ) ) {
2335 return false;
2336 }
2337
2338 $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page );
2339 $elmap = ElementorDataMap::instance();
2340 $ajax = [];
2341
2342 foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) {
2343 $ajax[] = ! isset( $data['settings']['active_filter'] );
2344
2345 }
2346
2347 return ! empty( $ajax[0] );
2348 }
2349
2350 /**
2351 * Get WooCommerce product categories.
2352 *
2353 * @param string|null $search_query The search string for category names.
2354 *
2355 * @return array An array of product categories with 'value' and 'label' keys.
2356 */
2357 public static function products_category_query( $search_query = null ) {
2358 if ( ! is_admin() ) {
2359 return [];
2360 }
2361
2362 $cache_key = 'rtsb_product_categories_' . md5( serialize( $search_query ) );
2363
2364 if ( isset( self::$cache[ $cache_key ] ) ) {
2365 return self::$cache[ $cache_key ];
2366 }
2367
2368 $results = wp_cache_get( $cache_key );
2369
2370 if ( ! $results ) {
2371 global $wpdb;
2372 $sql = "SELECT t.term_id, t.name
2373 FROM {$wpdb->terms} t
2374 JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
2375 WHERE tt.taxonomy = 'product_cat'";
2376 if ( $search_query ) {
2377 $sql .= ' AND t.name LIKE %s';
2378 $prepared_sql = $wpdb->prepare( $sql, '%' . $wpdb->esc_like( $search_query ) . '%' ); // Escaping and wildcard
2379 } else {
2380 $prepared_sql = $sql; // No need for placeholders
2381 }
2382 $results = $wpdb->get_results( $prepared_sql );
2383 // Cache the results in the object cache for future use
2384 wp_cache_set( $cache_key, $results ); // Adjust the expiration time as needed
2385 }
2386
2387 $cats = [];
2388 if ( ! is_array( $results ) && ! count( $results ) ) {
2389 return $cats;
2390 }
2391 foreach ( $results as $row ) {
2392 $category_id = $row->term_id;
2393 $category_title = $row->name;
2394
2395 $cats[] = [
2396 'value' => $category_id,
2397 'label' => $category_title,
2398 ];
2399 }
2400
2401 // Cache the results in a static variable for the next call
2402 self::$cache[ $cache_key ] = $cats;
2403 return $cats;
2404 }
2405
2406 /**
2407 * @param $search_query
2408 *
2409 * @return array
2410 */
2411 public static function get_registered_post_types( $search_query = null ) {
2412 // Get all registered post types
2413 $registered_post_types = get_post_types(
2414 [
2415 'public' => true,
2416 '_builtin' => false,
2417 ],
2418 'objects'
2419 );
2420
2421 unset( $registered_post_types['elementor_library'] );
2422 unset( $registered_post_types['e-landing-page'] );
2423 unset( $registered_post_types['rtsb_builder'] );
2424
2425 $post_types = [];
2426
2427 // Check if a search query is provided
2428 if ( ! empty( $search_query ) ) {
2429 // Filter post types based on the search query
2430 $registered_post_types = array_filter(
2431 $registered_post_types,
2432 function ( $post_type ) use ( $search_query ) {
2433 return stripos( $post_type->labels->singular_name, $search_query ) !== false;
2434 }
2435 );
2436 // Check if 'post' match the search query and include them if they do
2437 if ( stripos( 'post', $search_query ) !== false ) {
2438 $post_types[] = [
2439 'value' => 'post',
2440 'label' => 'Post',
2441 ];
2442 }
2443 } else {
2444 $post_types[] = [
2445 'value' => 'post',
2446 'label' => 'Post',
2447 ];
2448 }
2449
2450 // Convert the filtered post types to an array
2451 foreach ( $registered_post_types as $post_type ) {
2452 $post_types[] = [
2453 'value' => $post_type->name,
2454 'label' => $post_type->labels->singular_name,
2455 ];
2456 }
2457
2458 return $post_types;
2459 }
2460
2461 /**
2462 * Get Post Types.
2463 *
2464 * @param $search_query
2465 *
2466 * @return array
2467 */
2468 public static function get_post_types( $search_query = null, $args = [] ) {
2469
2470 $args = wp_parse_args(
2471 $args,
2472 [
2473 'post_type' => 'any',
2474 'posts_per_page' => 20,
2475 'orderby' => 'ID',
2476 'order' => 'DESC',
2477 ]
2478 );
2479
2480 if ( 'archive' !== $args['post_type'] ) {
2481 if ( $search_query ) {
2482 $args['s'] = $search_query;
2483 }
2484 $posts = [];
2485 $query_results = get_posts( $args );
2486 foreach ( $query_results as $post ) {
2487 $posts[] = [
2488 'value' => $post->ID,
2489 'label' => $post->post_title,
2490 ];
2491 }
2492 if ( $search_query ) {
2493 if ( strpos( '-error 404', $search_query ) ) {
2494 $posts[] = [
2495 'value' => 'error',
2496 'label' => __( '404 Error', 'shopbuilder' ),
2497 ];
2498 }
2499 } else {
2500 $posts[] = [
2501 'value' => 'error',
2502 'label' => __( '404 Error', 'shopbuilder' ),
2503 ];
2504 }
2505 } else {
2506 $posts = self::get_registered_post_types( $search_query );
2507 }
2508
2509 return $posts;
2510 }
2511
2512 /**
2513 * Get all Elementor breakpoints.
2514 *
2515 * @return array
2516 */
2517 public static function get_elementor_breakpoints() {
2518 return ( new \Elementor\Core\Breakpoints\Manager() )->get_breakpoints_config();
2519 }
2520
2521 /**
2522 * Render view.
2523 *
2524 * @param string $viewName View name.
2525 * @param array $args View args.
2526 * @param boolean $return View return.
2527 * @return string|void
2528 */
2529 public static function renderView( $viewName, $args = [], $return = false ) {
2530 $viewName = str_replace( '.', '/', $viewName );
2531
2532 if ( ! empty( $args ) && is_array( $args ) ) {
2533 extract( $args );
2534 }
2535
2536 $view_file = rtsb()->plugin_path() . '/resources/' . $viewName . '.php';
2537
2538 if ( ! file_exists( $view_file ) ) {
2539 _doing_it_wrong( __FUNCTION__, sprintf( '<code>%s</code> does not exist.', esc_html( $view_file ) ), '1.7.0' );
2540
2541 return;
2542 }
2543
2544 if ( $return ) {
2545 ob_start();
2546 include $view_file;
2547
2548 return ob_get_clean();
2549 } else {
2550 include $view_file;
2551 }
2552 }
2553 /**
2554 * @param int $limit Best-selling Base on product Limit.
2555 * @param string $return_type id|Object
2556 *
2557 * @return int
2558 */
2559 public static function best_selling_products( $limit = 10, $return_type = 'id' ) {
2560 $cache_key = 'best_selling_products' . $return_type . $limit;
2561 // if ( isset( self::$cache[ $cache_key ] ) ) {
2562 // return self::$cache[ $cache_key ];
2563 // }
2564 // Check if the data is in the cache
2565 $cached_data = get_transient( $cache_key );
2566 if ( $cached_data ) {
2567 return $cached_data;
2568 }
2569
2570 $args = [
2571 'limit' => $limit,
2572 'orderby' => 'total_sales',
2573 ];
2574 if ( 'id' === strtolower( $return_type ) ) {
2575 $args['return'] = 'ids';
2576 }
2577 $best_selling = wc_get_products( $args );
2578 // self::$cache[ $cache_key ] = $best_selling;
2579 // Cache the result for future use
2580 set_transient( $cache_key, $best_selling, DAY_IN_SECONDS );
2581
2582 return $best_selling;
2583 }
2584
2585 /**
2586 * @param null|Object $product Product Object.
2587 * @param int $days_threshold Date String.
2588 *
2589 * @return bool
2590 */
2591 public static function is_new_product( $product = null, $days_threshold = 30 ) {
2592 if ( is_null( $product ) ) {
2593 global $product;
2594 }
2595 if ( ! $product instanceof WC_Product ) {
2596 return false;
2597 }
2598
2599 $product_id = $product->get_id();
2600 $days_threshold = ! empty( $days_threshold ) ? $days_threshold : 30;
2601 $cache_key = 'is_new_product_' . $product_id . '_' . $days_threshold;
2602
2603 if ( isset( self::$cache[ $cache_key ] ) ) {
2604 return self::$cache[ $cache_key ];
2605 }
2606
2607 // Get the product publish date
2608 $publish_timestamp = strtotime( $product->get_date_created()->date_i18n( 'Y-m-d H:i:s' ) );
2609
2610 // Calculate the difference in days
2611 $days_difference = abs( time() - $publish_timestamp ) / ( 60 * 60 * 24 );
2612
2613 // Check if the product is considered new
2614 $is_new = $days_difference <= $days_threshold;
2615
2616 // Cache the result for a day
2617 self::$cache[ $cache_key ] = $is_new;
2618
2619 return $is_new;
2620 }
2621 }
2622