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

3,279 lines 96.9 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 public static function get_nonce() {
49 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
50 return isset( $_REQUEST[ rtsb()->nonceId ] ) ? sanitize_text_field( $_REQUEST[ rtsb()->nonceId ] ) : null;
51 }
52
53 /**
54 * Set Cookie or Session
55 *
56 * @param $name
57 * @param $value
58 */
59 public static function setSession( $name, $value ) {
60 if ( ! headers_sent() && session_status() == PHP_SESSION_NONE ) {
61 session_start();
62 $_SESSION[ $name ] = $value;
63 } else {
64 $_SESSION[ $name ] = $value;
65 }
66 }
67 /**
68 * Get Cookie or Session
69 *
70 * @param $name
71 *
72 * @return bool
73 */
74 public static function getSession( $name ) {
75 if ( ! headers_sent() && session_status() == PHP_SESSION_NONE ) {
76 session_start();
77 }
78 return $_SESSION[ $name ] ?? null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
79 }
80 /**
81 * Remove Session Variable
82 *
83 * @param string $name The name of the session variable to remove.
84 */
85 public static function removeSession( $name ) {
86 if ( ! headers_sent() && session_status() == PHP_SESSION_NONE ) {
87 session_start();
88 unset( $_SESSION[ $name ] );
89 } else {
90 unset( $_SESSION[ $name ] );
91 }
92 }
93
94 /**
95 * @param $plugin_slug
96 *
97 * @return bool
98 */
99 public static function check_plugin_installed( $plugin_slug ): bool {
100 $installed_plugins = get_plugins();
101
102 return array_key_exists( $plugin_slug, $installed_plugins ) || in_array( $plugin_slug, $installed_plugins, true );
103 }
104
105 /**
106 * @param $plugin_slug
107 *
108 * @return bool
109 */
110 public static function check_plugin_active( $plugin_slug ): bool {
111 if ( is_plugin_active( $plugin_slug ) ) {
112 return true;
113 }
114
115 return false;
116 }
117 /**
118 * Get all user roles.
119 *
120 * @return array|false|mixed
121 */
122 public static function get_current_user_roles() {
123 $current_user = wp_get_current_user();
124 return $current_user->roles;
125 }
126 /**
127 * Get all user roles.
128 *
129 * @return array|false|mixed
130 */
131 public static function get_all_user_roles() {
132 $cache_key = 'rtsb_get_user_roles';
133 $roles = wp_cache_get( $cache_key, 'shopbuilder' );
134
135 if ( empty( $roles ) ) {
136 if ( ! function_exists( 'get_editable_roles' ) ) {
137 require_once ABSPATH . 'wp-admin/includes/user.php';
138 }
139
140 $user_roles = \get_editable_roles();
141 $roles = [];
142
143 foreach ( $user_roles as $key => $role ) {
144 if ( empty( $role['capabilities'] ) ) {
145 continue;
146 }
147 $roles[ $key ] = $role['name'];
148 }
149 }
150 wp_cache_set( $cache_key, $roles, 'shopbuilder' );
151 Cache::set_data_cache_key( $cache_key );
152 return $roles;
153 }
154
155 /**
156 * @param $data
157 *
158 * @return mixed|string
159 */
160 public static function stripslashes_value( $data ) {
161 if ( is_string( $data ) && strpos( $data, '\\' ) !== false ) {
162 return stripslashes( $data );
163 } elseif ( is_array( $data ) ) {
164 foreach ( $data as $key => $value ) {
165 $data[ $key ] = self::stripslashes_value( $value );
166 }
167 }
168
169 return $data;
170 }
171
172 /**
173 * @param $string
174 *
175 * @return array
176 */
177 public static function multiselect_settings_field_value( $string ) {
178
179 $values = [];
180 if ( empty( $string ) ) {
181 return $values;
182 }
183
184 $stripslashes_data = self::stripslashes_value( $string );
185 if ( is_array( $stripslashes_data ) && count( $stripslashes_data ) ) {
186 foreach ( $stripslashes_data as $item ) {
187 $item = is_array( $item ) ? $item : json_decode( $item, true );
188 $values[] = $item['value'];
189 }
190 }
191
192 return $values;
193 }
194
195 /**
196 * @return bool
197 */
198 public static function check_is_block_theme(): bool {
199 global $wp_version;
200
201 return version_compare( $wp_version, '5.9', '>=' ) && function_exists( 'wp_is_block_theme' ) && wp_is_block_theme();
202 }
203
204 /**
205 * @param string $template_name Template name.
206 * @param string $template_path Template path. (default: '').
207 * @param string $plugin_path Plugin path. (default: ''). fallback file from plugin.
208 *
209 * @return mixed|void
210 */
211 public static function locate_template( $template_name, $template_path = '', $plugin_path = '' ) {
212 $template_name = self::sanitize_file_name( $template_name ) . '.php';
213
214 if ( ! $template_path ) {
215 $template_path = rtsb()->get_template_path();
216 }
217 if ( ! $plugin_path ) {
218 $plugin_path = RTSB_ABSPATH . 'templates/';
219 }
220
221 $template_rtsb_path = trailingslashit( $template_path ) . $template_name;
222 $template_path = '/' . $template_name;
223 $plugin_path = $plugin_path . $template_name;
224 $pro_plugin_path = rtsb()->has_pro() ? RTSBPRO_PATH . 'templates/' . $template_name : '';
225
226 $located = locate_template(
227 apply_filters(
228 'rtsb/core/locate_template_files',
229 [
230 $template_rtsb_path, // Search in <theme>/shopbuilder/.
231 $template_path, // Search in <theme>/.
232 ]
233 )
234 );
235
236 if ( ! $located ) {
237 if ( file_exists( $plugin_path ) ) {
238 return apply_filters( 'rtsb/core/locate_template', $plugin_path, $template_name );
239 } elseif ( $pro_plugin_path && rtsb()->has_pro() && file_exists( $pro_plugin_path ) ) {
240 return apply_filters( 'rtsb/core/locate_template', $pro_plugin_path, $template_name );
241 }
242 }
243
244 /**
245 * APPLY_FILTERS: rtsb/core/locate_template
246 *
247 * Filter the location of the templates.
248 *
249 * @param string $located Template found
250 * @param string $path Template path
251 *
252 * @return string
253 */
254 return apply_filters( 'rtsb/core/locate_template', $located, $template_name );
255 }
256
257 /**
258 * Remove any character that is not alphanumeric, /, _, or -.
259 *
260 * @param string $name Name to sanitize.
261 *
262 * @return array|string|string[]|null
263 */
264 private static function sanitize_file_name( $name ) {
265 return preg_replace( '/[^a-zA-Z0-9\/_\-]/', '', $name );
266 }
267
268 /**
269 * Template Content
270 *
271 * @param string $template_name Template name.
272 * @param array $args Arguments. (default: array).
273 * @param bool $return Whether to return or print the template.
274 * @param string $template_path Template path. (default: '').
275 * @param string $plugin_path Fallback path from where file will load if fail to load from template. (default: '').
276 *
277 * @return false|string|void
278 */
279 public static function load_template( $template_name, array $args = null, $return = false, $template_path = '', $plugin_path = '' ) {
280 $cache_key = sanitize_key( implode( '-', [ 'template', $template_name, $template_path ] ) );
281 $located = (string) wp_cache_get( $cache_key, 'shopbuilder' );
282 if ( ! $located ) {
283 $located = self::locate_template( $template_name, $template_path, $plugin_path );
284 // Don't cache the absolute path so that it can be shared between web servers with different paths.
285 $cache_path = wc_tokenize_path( $located, wc_get_path_define_tokens() );
286 Cache::set_template_cache( $cache_key, $cache_path );
287 } else {
288 // Make sure that the absolute path to the template is resolved.
289 $located = wc_untokenize_path( $located, wc_get_path_define_tokens() );
290 }
291 if ( ! file_exists( $located ) ) {
292 // translators: %s template.
293 self::doing_it_wrong( __FUNCTION__, sprintf( __( '%s does not exist.', 'shopbuilder' ), '<code>' . $located . '</code>' ), '1.0' );
294
295 return;
296 }
297
298 if ( ! empty( $args ) && is_array( $args ) ) {
299 $atts = $args;
300 extract( $args ); // @codingStandardsIgnoreLine
301 }
302
303 // Allow 3rd party plugin filter template file from their plugin.
304 $located = apply_filters( 'rtsb/core/get_template', $located, $template_name, $args );
305
306 if ( $return ) {
307 ob_start();
308 }
309
310 do_action( 'rtsb/core/before_template_part', $template_name, $located, $args );
311 include $located;
312
313 do_action( 'rtsb/core/after_template_part', $template_name, $located, $args );
314
315 if ( $return ) {
316 return ob_get_clean();
317 }
318 }
319
320 /**
321 * Verify nonce.
322 *
323 * @return string
324 */
325 public static function is_woocommerce() {
326 return is_woocommerce() || is_cart() || is_checkout() || is_account_page();
327 }
328
329 /**
330 * Page builder
331 *
332 * @param int $post_id post id.
333 *
334 * @return string
335 */
336 public static function page_edit_with( $post_id ) {
337 if ( ! $post_id ) {
338 return '';
339 }
340
341 $edit_with = get_post_meta( $post_id, '_elementor_edit_mode', true );
342
343 if ( 'builder' === $edit_with ) {
344 $edit_by = 'elementor';
345 } else {
346 $edit_by = 'gutenberg';
347 }
348
349 return $edit_by;
350 }
351
352 /**
353 * Returns default expiration for wishlist cookie
354 *
355 * @return int Number of seconds the cookie should last.
356 */
357 public static function get_cookie_expiration() {
358 return intval( apply_filters( 'rtsb/cookie_expiration', 60 * 60 * 24 * 30 ) );
359 }
360
361 /**
362 * Create a cookie.
363 *
364 * @param string $name Cookie name.
365 * @param mixed $value Cookie value.
366 * @param int $time Cookie expiration time.
367 * @param bool $secure Whether cookie should be available to secured connection only.
368 * @param bool $httponly Whether cookie should be available to HTTP request only (no js handling).
369 *
370 * @return bool
371 * @since 1.0.0
372 */
373 public static function setcookie( $name, $value = [], $time = null, $secure = false, $httponly = false ) {
374
375 if ( ! apply_filters( 'rtsb/set_cookie', true ) || empty( $name ) ) {
376 return false;
377 }
378
379 $time = ! empty( $time ) ? $time : time() + self::get_cookie_expiration();
380
381 $value = wp_json_encode( stripslashes_deep( $value ) );
382 $expiration = apply_filters( 'rtsb/cookie_expiration_time', $time ); // Default 30 days.
383
384 $_COOKIE[ $name ] = $value;
385 wc_setcookie( $name, $value, $expiration, $secure, $httponly );
386
387 return true;
388 }
389
390 /**
391 * Retrieve the value of a cookie.
392 *
393 * @param string $name Cookie name.
394 *
395 * @return mixed
396 * @since 1.0.0
397 */
398 public static function getcookie( $name ) {
399 if ( isset( $_COOKIE[ $name ] ) ) {
400 return json_decode( sanitize_text_field( wp_unslash( $_COOKIE[ $name ] ) ), true );
401 }
402
403 return [];
404 }
405
406 /**
407 * Woocommerce Last product id return
408 */
409 public static function get_prepared_product_id() {
410 if ( is_singular( 'product' ) ) {
411 return get_the_ID();
412 }
413 // Return the Builder Template id.
414
415 if ( get_post_type( get_the_ID() ) == BuilderFns::$post_type_tb ) {
416 $product_id = get_post_meta( get_the_ID(), BuilderFns::$product_template_meta, true );
417 if ( $product_id && get_post_status( $product_id ) ) {
418 return $product_id;
419 }
420 }
421
422 global $wpdb;
423 $cache_key = 'rtsb_prepared_product_id';
424 $_post_id = wp_cache_get( $cache_key, 'shopbuilder' );
425 if ( false === $_post_id || 'publish' !== get_post_status( $_post_id ) ) {
426 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
427 $_post_id = $wpdb->get_var(
428 $wpdb->prepare( "SELECT MAX(ID) FROM {$wpdb->prefix}posts WHERE post_type = %s AND post_status IN('publish', 'draft')", 'product' )
429 );
430 wp_cache_set( $cache_key, $_post_id, 'shopbuilder', 12 * HOUR_IN_SECONDS );
431 Cache::set_data_cache_key( $cache_key );
432 }
433
434 return $_post_id;
435 }
436
437 /**
438 * Get the product function. Only used in single page widgets.
439 *
440 * @return object
441 */
442 public static function get_product() {
443 global $product;
444
445 if ( is_singular( 'product' ) && $product instanceof WC_Product ) {
446 // do_action( 'rtsb_before_product_template_render' );.
447 return $product;
448 }
449 $cache_key = 'prepared_product_for_preview';
450 if ( isset( self::$cache[ $cache_key ] ) ) {
451 return self::$cache[ $cache_key ];
452 }
453 $product = wc_get_product( self::get_prepared_product_id() );
454 self::$cache[ $cache_key ] = $product;
455 do_action( 'rtsb_before_product_template_render' );
456 return $product;
457 }
458
459 /**
460 * Error function
461 *
462 * @param [type] $function function name.
463 * @param [type] $message message.
464 * @param [type] $version version.
465 *
466 * @return void
467 */
468 public static function doing_it_wrong( $function, $message, $version ) {
469 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_wp_debug_backtrace_summary
470 $message .= ' Backtrace: ' . wp_debug_backtrace_summary();
471 _doing_it_wrong( esc_html( $function ), wp_kses_post( $message ), esc_html( $version ) );
472 }
473
474 /**
475 * @return array
476 */
477 public static function get_pages() {
478 $pages = [];
479 $rawPages = get_pages();
480 if ( ! empty( $rawPages ) ) {
481 foreach ( $rawPages as $page ) {
482 $pages[ $page->ID ] = $page->post_title;
483 }
484 }
485
486 return $pages;
487 }
488
489 public static function get_section_items( $section_id ) {
490 if ( ! $section_id ) {
491 return [];
492 }
493
494 return DataModel::source()->get_option( $section_id, [] );
495 }
496
497 public static function get_options( $section_id, $item_id ) {
498 if ( ! $section_id || ! $item_id ) {
499 return [];
500 }
501 $sections = self::get_section_items( $section_id );
502
503 return isset( $sections[ $item_id ] ) ? $sections[ $item_id ] : [];
504 }
505
506 /**
507 * Get options value with default value if options doesn't exist.
508 *
509 * @param $group
510 * @param $option_key
511 * @param $default_value
512 *
513 * @return mixed|string
514 */
515 public static function get_options_by_default_val( $group, $option_key, $default_value = '' ) {
516
517 if ( ! $option_key || ! isset( $group[ $option_key ] ) ) {
518 return $default_value;
519 }
520
521 return $group[ $option_key ];
522 }
523
524 /**
525 * @param string $section_id
526 * @param string $item_id
527 * @param string $option_id
528 * @param null $default EXCEPT multi_checkbox you can provide default value if given option does not set any value
529 * @param null $type checkbox, multi_checkbox, number
530 *
531 * @return bool|int|mixed|null
532 */
533 public static function get_option( $section_id, $item_id, $option_id, $default = null, $type = null ) {
534 $options = self::get_options( $section_id, $item_id );
535
536 if ( $type === 'checkbox' ) {
537 if ( isset( $options[ $option_id ] ) ) {
538 return $options[ $option_id ] === 'on';
539 }
540
541 return $default;
542 } elseif ( $type === 'multi_checkbox' ) {
543 return isset( $options[ $option_id ] ) && is_array( $options[ $option_id ] ) && in_array( $default, $options[ $option_id ] );
544 } elseif ( $type === 'number' ) {
545 return isset( $options[ $option_id ] ) ? absint( $options[ $option_id ] ) : absint( $default );
546 }
547
548 return isset( $options[ $option_id ] ) && ! empty( $options[ $option_id ] ) ? $options[ $option_id ] : $default;
549 }
550
551
552 /**
553 * Create a page and store the ID in an option.
554 *
555 * @param mixed $slug Slug for the new page.
556 * @param array $options ['section_id', 'item_id', 'option_id']Option name to store the page's ID.
557 * @param string $page_title (default: '') Title for the new page.
558 * @param string $page_content (default: '') Content for the new page.
559 * @param int $post_parent (default: 0) Parent for the new page.
560 * @param string $post_status (default: publish) The post status of the new page.
561 *
562 * @return int page ID.
563 */
564 public static function create_page( $slug, $options = '', $page_title = '', $page_content = '', $post_parent = 0, $post_status = 'publish' ) {
565 global $wpdb;
566
567 $option_value = 0;
568 if ( ! empty( $options ) ) {
569 if ( is_array( $options ) ) {
570 $options = wp_parse_args(
571 $options,
572 [
573 'section_id' => '',
574 'item_id' => '',
575 'option_id' => '',
576 ]
577 );
578 $option_value = self::get_option( $options['section_id'], $options['item_id'], $options['option_id'], 0, 'number' );
579 } else {
580 $option_value = absint( get_option( $options ) );
581 }
582 }
583
584 if ( $option_value > 0 ) {
585 $page_object = get_post( $option_value );
586
587 if ( $page_object && 'page' === $page_object->post_type && ! in_array(
588 $page_object->post_status,
589 [
590 'pending',
591 'trash',
592 'future',
593 'auto-draft',
594 ],
595 true
596 ) ) {
597 // Valid page is already in place.
598 return $page_object->ID;
599 }
600 }
601
602 if ( strlen( $page_content ) > 0 ) {
603 // Search for an existing page with the specified page content (typically a shortcode).
604 $shortcode = str_replace( [ '<!-- wp:shortcode -->', '<!-- /wp:shortcode -->' ], '', $page_content );
605 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
606 $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}%" ) );
607 } else {
608 // Search for an existing page with the specified page slug.
609 $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 ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
610 }
611
612 $valid_page_found = apply_filters( 'rtsb/core/create_page_id', $valid_page_found, $slug, $page_content, $options );
613
614 if ( $valid_page_found ) {
615 if ( is_array( $options ) ) {
616 if ( ! empty( $options['section_id'] ) && $options['item_id'] && $options['option_id'] ) {
617 $section_items = DataModel::source()->get_option( $options['section_id'], [] );
618 $section_items[ $options['item_id'] ][ $options['option_id'] ] = $valid_page_found;
619 DataModel::source()->set_option( $options['section_id'], $section_items );
620 }
621 } else {
622 if ( $options ) {
623 update_option( $options, $valid_page_found );
624 }
625 }
626
627 return $valid_page_found;
628 }
629
630 // Search for a matching valid trashed page.
631 if ( strlen( $page_content ) > 0 ) {
632 // Search for an existing page with the specified page content (typically a shortcode).
633 $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}%" ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
634 } else {
635 // Search for an existing page with the specified page slug.
636 $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 ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
637 }
638
639 if ( $trashed_page_found ) {
640 $page_id = $trashed_page_found;
641 $page_data = [
642 'ID' => $page_id,
643 'post_status' => $post_status,
644 ];
645 wp_update_post( $page_data );
646 } else {
647 $page_data = [
648 'post_status' => $post_status,
649 'post_type' => 'page',
650 'post_author' => 1,
651 'post_name' => $slug,
652 'post_title' => $page_title,
653 'post_content' => $page_content,
654 'post_parent' => $post_parent,
655 'comment_status' => 'closed',
656 ];
657 $page_id = wp_insert_post( $page_data );
658
659 do_action( 'rtsb/core/page_created', $page_id, $page_data );
660 }
661
662 if ( is_array( $options ) ) {
663 if ( ! empty( $options['section_id'] ) && $options['item_id'] && $options['option_id'] ) {
664 $section_items = DataModel::source()->get_option( $options['section_id'], [] );
665 $section_items[ $options['item_id'] ][ $options['option_id'] ] = $page_id;
666 DataModel::source()->set_option( $options['section_id'], $section_items );
667 }
668 } else {
669 if ( $options ) {
670 update_option( $options, $page_id );
671 }
672 }
673
674 return $page_id;
675 }
676
677 public static function get_kses_array() {
678 return [
679 'a' => [
680 'class' => [],
681 'href' => [],
682 'rel' => [],
683 'title' => [],
684 ],
685 'abbr' => [
686 'title' => [],
687 ],
688 'b' => [],
689 'blockquote' => [
690 'cite' => [],
691 ],
692 'cite' => [
693 'title' => [],
694 ],
695 'code' => [],
696 'del' => [
697 'datetime' => [],
698 'title' => [],
699 ],
700 'dd' => [],
701 'div' => [
702 'class' => [],
703 'title' => [],
704 'style' => [],
705 ],
706 'dl' => [],
707 'dt' => [],
708 'em' => [],
709 'h1' => [
710 'class' => [],
711 ],
712 'h2' => [
713 'class' => [],
714 ],
715 'h3' => [
716 'class' => [],
717 ],
718 'h4' => [
719 'class' => [],
720 ],
721 'h5' => [
722 'class' => [],
723 ],
724 'h6' => [
725 'class' => [],
726 ],
727 'i' => [
728 'class' => [],
729 ],
730 'img' => [
731 'alt' => [],
732 'class' => [],
733 'height' => [],
734 'src' => [],
735 'width' => [],
736 ],
737 'li' => [
738 'class' => [],
739 ],
740 'ol' => [
741 'class' => [],
742 ],
743 'p' => [
744 'class' => [],
745 ],
746 'q' => [
747 'cite' => [],
748 'title' => [],
749 ],
750 'span' => [
751 'class' => [],
752 'title' => [],
753 'style' => [],
754 ],
755 'iframe' => [
756 'width' => [],
757 'height' => [],
758 'scrolling' => [],
759 'frameborder' => [],
760 'allow' => [],
761 'src' => [],
762 ],
763 'strike' => [],
764 'br' => [],
765 'strong' => [],
766 'data-wow-duration' => [],
767 'data-wow-delay' => [],
768 'data-wallpaper-options' => [],
769 'data-stellar-background-ratio' => [],
770 'ul' => [
771 'class' => [],
772 ],
773 ];
774 }
775
776
777 /*
778 * Escape output of wishlist icon
779 *
780 * @param string $data Data to escape.
781 * @return string Escaped data
782 */
783 public static function print_icon( $data ) {
784 /**
785 * APPLY_FILTERS: rtsb/core/allowed_icon_html
786 *
787 * Filter the allowed HTML for the icons.
788 *
789 * @param array $allowed_icon_html Allowed HTML
790 *
791 * @return array
792 */
793 $allowed_icon_html = apply_filters(
794 'rtsb/core/allowed_icon_html',
795 [
796 'i' => [
797 'class' => true,
798 ],
799 'img' => [
800 'src' => true,
801 'alt' => true,
802 'width' => true,
803 'height' => true,
804 ],
805 'svg' => [
806 'class' => true,
807 'aria-hidden' => true,
808 'aria-labelledby' => true,
809 'role' => true,
810 'xmlns' => true,
811 'width' => true,
812 'height' => true,
813 'viewbox' => true,
814 'stroke' => true,
815 'fill' => true,
816 ],
817 'g' => [
818 'fill' => true,
819 ],
820 'title' => [
821 'title' => true,
822 ],
823 'path' => [
824 'd' => true,
825 'fill' => true,
826 'stroke' => true,
827 'stroke-width' => true,
828 'stroke-linecap' => true,
829 'stroke-linejoin' => true,
830 'fill-rule' => true,
831 'clip-rule' => true,
832 ],
833 ]
834 );
835
836 echo wp_kses( $data, $allowed_icon_html );
837 }
838
839 /**
840 * Prints HTMl.
841 *
842 * @param string $html HTML.
843 * @param bool $allHtml All HTML.
844 *
845 * @return void
846 */
847 public static function print_html( $html, $allHtml = false ) {
848 if ( ! $html ) {
849 return;
850 }
851 if ( $allHtml ) {
852 echo stripslashes_deep( $html ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
853 } else {
854 echo wp_kses_post( stripslashes_deep( $html ) );
855 }
856 }
857
858 /**
859 * Allowed HTML for wp_kses.
860 *
861 * @param string $level Tag level.
862 *
863 * @return mixed
864 */
865 public static function allowedHtml( $level = 'basic' ) {
866 $allowed_html = [];
867 // TODO:: Need Optimize.
868 switch ( $level ) {
869 case 'basic':
870 $allowed_html = [
871 'b' => [
872 'class' => [],
873 'id' => [],
874 ],
875 'i' => [
876 'class' => [],
877 'id' => [],
878 ],
879 'u' => [
880 'class' => [],
881 'id' => [],
882 ],
883 'br' => [
884 'class' => [],
885 'id' => [],
886 ],
887 'em' => [
888 'class' => [],
889 'id' => [],
890 ],
891 'span' => [
892 'class' => [],
893 'id' => [],
894 ],
895 'strong' => [
896 'class' => [],
897 'id' => [],
898 ],
899 'hr' => [
900 'class' => [],
901 'id' => [],
902 ],
903 'div' => [
904 'class' => [],
905 'id' => [],
906 ],
907 'a' => [
908 'href' => [],
909 'title' => [],
910 'class' => [],
911 'id' => [],
912 'target' => [],
913 ],
914 ];
915 break;
916
917 case 'advanced':
918 $allowed_html = [
919 'b' => [
920 'class' => [],
921 'id' => [],
922 ],
923 'i' => [
924 'class' => [],
925 'id' => [],
926 ],
927 'u' => [
928 'class' => [],
929 'id' => [],
930 ],
931 'br' => [
932 'class' => [],
933 'id' => [],
934 ],
935 'em' => [
936 'class' => [],
937 'id' => [],
938 ],
939 'span' => [
940 'class' => [],
941 'id' => [],
942 ],
943 'strong' => [
944 'class' => [],
945 'id' => [],
946 ],
947 'hr' => [
948 'class' => [],
949 'id' => [],
950 ],
951 'a' => [
952 'href' => [],
953 'title' => [],
954 'class' => [],
955 'id' => [],
956 'target' => [],
957 ],
958 'input' => [
959 'type' => [],
960 'name' => [],
961 'class' => [],
962 'value' => [],
963 ],
964 ];
965 break;
966
967 case 'image':
968 $allowed_html = [
969 'img' => [
970 'src' => [],
971 'data-src' => [],
972 'alt' => [],
973 'height' => [],
974 'width' => [],
975 'class' => [],
976 'id' => [],
977 'style' => [],
978 'srcset' => [],
979 'loading' => [],
980 'sizes' => [],
981 ],
982 'div' => [
983 'class' => [],
984 ],
985 ];
986 break;
987
988 case 'anchor':
989 $allowed_html = [
990 'a' => [
991 'href' => [],
992 'title' => [],
993 'class' => [],
994 'id' => [],
995 'style' => [],
996 ],
997 ];
998 break;
999
1000 default:
1001 // code...
1002 break;
1003 }
1004
1005 return $allowed_html;
1006 }
1007
1008 /**
1009 * Safe get a validated HTML tag.
1010 *
1011 * @param string $tag HTML tag.
1012 *
1013 * @return string
1014 */
1015 public static function get_validated_html_tag( $tag ) {
1016 $allowed_html_wrapper_tags = [
1017 'a',
1018 'article',
1019 'aside',
1020 'button',
1021 'div',
1022 'footer',
1023 'h1',
1024 'h2',
1025 'h3',
1026 'h4',
1027 'h5',
1028 'h6',
1029 'header',
1030 'main',
1031 'nav',
1032 'p',
1033 'section',
1034 'span',
1035 ];
1036
1037 return in_array( strtolower( $tag ), $allowed_html_wrapper_tags, true ) ? $tag : 'div';
1038 }
1039
1040 /**
1041 * Safe print a validated HTML tag.
1042 *
1043 * @param string $tag HTML tag.
1044 *
1045 * @return void
1046 */
1047 public static function print_validated_html_tag( $tag ) {
1048 self::print_html( self::get_validated_html_tag( $tag ) );
1049 }
1050
1051 /**
1052 * Insert Some array element
1053 *
1054 * @param [type] $key The elements will insert nearby this key.
1055 * @param [type] $main_array Original array.
1056 * @param [type] $insert_array some element will insert in original array.
1057 * @param boolean $is_after array insert position base on the key.
1058 *
1059 * @return array
1060 */
1061 public static function insert_controls( $key, $main_array, $insert_array, $is_after = false ) {
1062 $index = array_search( $key, array_keys( $main_array ), true );
1063 if ( 'integer' === gettype( $index ) ) {
1064 if ( $is_after ) {
1065 $index++;
1066 }
1067 $main_array = array_merge(
1068 array_slice( $main_array, 0, $index ),
1069 $insert_array,
1070 array_slice( $main_array, $index )
1071 );
1072 }
1073
1074 return $main_array;
1075 }
1076
1077 /**
1078 * Image Sizes
1079 *
1080 * @return array
1081 */
1082 public static function get_image_sizes() {
1083 global $_wp_additional_image_sizes;
1084
1085 $sizes = [];
1086
1087 foreach ( get_intermediate_image_sizes() as $_size ) {
1088 if ( in_array( $_size, [ 'thumbnail', 'medium', 'large' ], true ) ) {
1089 $sizes[ $_size ]['width'] = get_option( "{$_size}_size_w" );
1090 $sizes[ $_size ]['height'] = get_option( "{$_size}_size_h" );
1091 $sizes[ $_size ]['crop'] = (bool) get_option( "{$_size}_crop" );
1092 } elseif ( isset( $_wp_additional_image_sizes[ $_size ] ) ) {
1093 $sizes[ $_size ] = [
1094 'width' => $_wp_additional_image_sizes[ $_size ]['width'],
1095 'height' => $_wp_additional_image_sizes[ $_size ]['height'],
1096 'crop' => $_wp_additional_image_sizes[ $_size ]['crop'],
1097 ];
1098 }
1099 }
1100
1101 $imgSize = [];
1102
1103 foreach ( $sizes as $key => $img ) {
1104 $imgSize[ $key ] = ucfirst( $key ) . " ({$img['width']}*{$img['height']})";
1105 }
1106
1107 $imgSize['full'] = esc_html__( 'Full size', 'shopbuilder' );
1108 $imgSize['rtsb_custom'] = esc_html__( 'Custom image size', 'shopbuilder' );
1109
1110 return $imgSize;
1111 }
1112
1113 /**
1114 * Free Layouts
1115 *
1116 * @return array
1117 */
1118 public static function free_layouts() {
1119 $layouts = [
1120 'grid-layout1' => esc_html__( 'Grid Layout 1', 'shopbuilder' ),
1121 'grid-layout2' => esc_html__( 'Grid Layout 2', 'shopbuilder' ),
1122 'list-layout1' => esc_html__( 'List Layout 1', 'shopbuilder' ),
1123 'list-layout2' => esc_html__( 'List Layout 2', 'shopbuilder' ),
1124 'slider-layout1' => esc_html__( 'Slider Layout 1', 'shopbuilder' ),
1125 'slider-layout2' => esc_html__( 'Slider Layout 2', 'shopbuilder' ),
1126 'category-single-layout1' => esc_html__( 'Category Single Layout 1', 'shopbuilder' ),
1127 'category-layout1' => esc_html__( 'Category Layout 1', 'shopbuilder' ),
1128 'category-layout2' => esc_html__( 'Category Layout 2', 'shopbuilder' ),
1129 ];
1130
1131 return apply_filters( 'rtsb/elements/elementor/free_layouts', $layouts );
1132 }
1133
1134 /**
1135 * Get all terms by taxonomy
1136 *
1137 * @param string $taxonomy Taxonomy name.
1138 * @param bool $placeholder Placeholder..
1139 *
1140 * @return array
1141 */
1142 public static function get_all_terms( $taxonomy, $placeholder = false ) {
1143 $terms = [];
1144
1145 if ( empty( $taxonomy ) ) {
1146 return $terms;
1147 }
1148 $cache_key = 'rtsb_get_all_terms_by_tax_name_' . $taxonomy;
1149 if ( isset( self::$cache[ $cache_key ] ) ) {
1150 return self::$cache[ $cache_key ];
1151 }
1152
1153 $termList = get_terms(
1154 [
1155 'taxonomy' => $taxonomy,
1156 'hide_empty' => false,
1157 ]
1158 );
1159
1160 if ( is_array( $termList ) && ! empty( $termList ) && empty( $termList['errors'] ) ) {
1161 if ( $placeholder ) {
1162 $terms = [
1163 'all' => __( 'All Products', 'shopbuilder' ),
1164 ];
1165 }
1166
1167 foreach ( $termList as $term ) {
1168 $terms[ $term->term_id ] = esc_html( $term->name );
1169 }
1170 }
1171 self::$cache[ $cache_key ] = $terms;
1172 return $terms;
1173 }
1174
1175 /**
1176 * Get all terms by attributes
1177 *
1178 * @return array
1179 */
1180 public static function get_all_attributes() {
1181 $terms = [];
1182 $termList = [];
1183
1184 $attributes = wc_get_attribute_taxonomies();
1185
1186 if ( $attributes ) {
1187 foreach ( $attributes as $tax ) {
1188 if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) ) {
1189 $termList[ $tax->attribute_name ] = get_terms( wc_attribute_taxonomy_name( $tax->attribute_name ) );
1190 }
1191 }
1192 }
1193
1194 if ( ! empty( $termList ) && empty( $termList['errors'] ) && is_array( $termList ) ) {
1195 foreach ( $termList as $name => $atts ) {
1196 foreach ( $atts as $term ) {
1197 $terms[ $term->term_id ] = esc_html( ucwords( str_replace( '-', ' ', $name ) ) . ' - ' . $term->name );
1198 }
1199 }
1200 }
1201
1202 return $terms;
1203 }
1204
1205 /**
1206 * Get all attributes name
1207 *
1208 * @return array
1209 */
1210 public static function get_all_attributes_name() {
1211 $attributes_name = [];
1212
1213 $attributes = wc_get_attribute_taxonomies();
1214
1215 if ( $attributes ) {
1216 foreach ( $attributes as $tax ) {
1217 if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) ) {
1218 $attributes_name[ wc_attribute_taxonomy_name( $tax->attribute_name ) ] = ucwords( $tax->attribute_name );
1219 }
1220 }
1221 }
1222
1223 return $attributes_name;
1224 }
1225
1226 /**
1227 * Get User list
1228 *
1229 * @return array
1230 */
1231 public static function get_users() {
1232 $users = [];
1233 $u = get_users();
1234
1235 if ( ! empty( $u ) ) {
1236 foreach ( $u as $user ) {
1237 $users[ $user->ID ] = $user->display_name;
1238 }
1239 }
1240
1241 return $users;
1242 }
1243
1244 /**
1245 * Get Taxonomy List.
1246 *
1247 * @return array
1248 */
1249 public static function get_tax_list() {
1250 return apply_filters(
1251 'rtsb/elements/tax_list',
1252 [
1253 'product_cat' => esc_html__( 'Product Category', 'shopbuilder' ),
1254 ]
1255 );
1256 }
1257
1258 /**
1259 * Get Category Query List.
1260 *
1261 * @return array
1262 */
1263 public static function get_cat_list() {
1264 return [
1265 'all' => esc_html__( 'All Categories', 'shopbuilder' ),
1266 'specific_parent' => esc_html__( 'Sub-Categories by Parent', 'shopbuilder' ),
1267 'cat_ids' => esc_html__( 'Select by ID', 'shopbuilder' ),
1268 'selection' => esc_html__( 'Manual Selection', 'shopbuilder' ),
1269 ];
1270 }
1271
1272 /**
1273 * Get Term List.
1274 *
1275 * @param string $taxonomy Taxonomy.
1276 * @param bool $first_term First term.
1277 * @param bool $only_parents Only parent terms.
1278 * @param bool $return_slug Return with slug.
1279 *
1280 * @return int|array
1281 */
1282 public static function get_terms( $taxonomy, $first_term = false, $only_parents = false, $return_slug = false ) {
1283 if ( ! is_admin() ) {
1284 return [];
1285 }
1286
1287 // TODO:: Return Slug always true for all settings.
1288 $term_list = [];
1289 $args = [
1290 'taxonomy' => $taxonomy,
1291 'hide_empty' => false,
1292 ];
1293
1294 if ( $only_parents ) {
1295 $args['parent'] = 0;
1296 }
1297
1298 $terms = get_terms( $args );
1299
1300 if ( empty( $terms ) ) {
1301 return [ esc_html__( 'Nothing found', 'shopbuilder' ) ];
1302 }
1303
1304 foreach ( $terms as $term ) {
1305 if ( $return_slug ) {
1306 $term_list[ $term->slug ] = $term->name;
1307 } else {
1308 $term_list[ $term->term_id ] = $term->name;
1309 }
1310 }
1311
1312 if ( $first_term ) {
1313 return array_keys( $term_list )[0];
1314 } else {
1315 return $term_list;
1316 }
1317 }
1318
1319 /**
1320 * Get product rating.
1321 *
1322 * @param array $args Arguments.
1323 *
1324 * @return string|void
1325 */
1326 public static function get_product_rating_html( $args = [] ) {
1327 global $product;
1328
1329 $html = '';
1330 $rating_count = $product->get_rating_count();
1331 $average_rating = $product->get_average_rating();
1332
1333 if ( ! rtsb()->has_pro() || empty( $args ) ) {
1334 if ( ! $rating_count || empty( wc_get_rating_html( $average_rating, $rating_count ) ) ) {
1335 return $html;
1336 }
1337
1338 $html .= '<div class="product-rating">';
1339 $html .= wc_get_rating_html( $average_rating, $rating_count );
1340 $html .= ! empty( $html ) ? '<span class="rtsb-count">(' . $average_rating . ')</span>' : '';
1341 $html .= '</div>';
1342
1343 self::print_html( $html, true );
1344
1345 return;
1346 }
1347
1348 if ( empty( $rating_count ) && ! $args['show_empty_rating'] ) {
1349 return '';
1350 }
1351
1352 $preset = ! empty( $args['preset'] ) ? $args['preset'] : 'preset1';
1353 $average = $args['show_average_rating'] ? '<span class="rtsb-count">(' . $average_rating . ')</span>' : '';
1354 $count = '';
1355
1356 if ( $args['show_rating_count'] ) {
1357 $count .= '<div class="rtsb-count">';
1358 $count .= sprintf(
1359 /* translators: %s is the number of reviews */
1360 _n( '%s Review', '%s Reviews', $rating_count, 'shopbuilder' ),
1361 $rating_count
1362 );
1363 $count .= '</div>';
1364 }
1365
1366 if ( 'preset2' === $preset ) {
1367 $average = $args['show_average_rating'] ? '<div class="inner-wrapper"><span class="star-icon"></span><span class="average-rating">' . $average_rating . '</span></div>' : '';
1368 }
1369
1370 $html .= '<div class="product-rating ' . esc_attr( $preset ) . '">';
1371
1372 if ( 'preset1' === $preset ) {
1373 $html .= wc_get_rating_html( $average_rating, $rating_count );
1374 $html .= $average;
1375 $html .= $count;
1376 } elseif ( 'preset2' === $preset ) {
1377 $html .= $average;
1378 $html .= $count;
1379 }
1380
1381 $html .= '</div>';
1382
1383 self::print_html( $html, true );
1384 }
1385
1386 public static function get_product_simple_rating_html() {
1387 global $product;
1388 $html = null;
1389 $rating_count = $product->get_rating_count();
1390 $average_rating = $product->get_average_rating();
1391 $html .= '<div class="product-rating">';
1392 $html .= wc_get_rating_html( $average_rating, $rating_count );
1393 $html .= ! empty( $html ) ? '<span class="rtsb-count">(' . $average_rating . ')</span>' : '';
1394 $html .= '</div>';
1395
1396 self::print_html( $html, true );
1397 }
1398
1399
1400
1401 /**
1402 * Text truncation.
1403 *
1404 * @param string $text_to_truncate Text.
1405 * @param int $limit Limit.
1406 * @param string $after After text.
1407 *
1408 * @return string
1409 */
1410 public static function text_truncation( $text_to_truncate, $limit, $after = '&#8230;' ) {
1411 if ( empty( $limit ) ) {
1412 return $text_to_truncate;
1413 }
1414
1415 $limit++;
1416
1417 $text = '';
1418
1419 if ( mb_strlen( $text_to_truncate ) > $limit ) {
1420 $subex = mb_substr( wp_strip_all_tags( $text_to_truncate ), 0, $limit );
1421 $exwords = explode( ' ', $subex );
1422 $excut = - ( mb_strlen( $exwords[ count( $exwords ) - 1 ] ) );
1423
1424 if ( $excut < 0 ) {
1425 $text .= mb_substr( $subex, 0, $excut ) . $after;
1426 } else {
1427 $text .= $subex . $after;
1428 }
1429 } else {
1430 $text .= $text_to_truncate;
1431 }
1432
1433 return $text;
1434 }
1435
1436 /**
1437 * Promo Badge HTML
1438 *
1439 * @param string $text Text.
1440 * @param string $class Class.
1441 *
1442 * @return void
1443 */
1444 public static function get_badge_html( $text, $class = 'fill' ) {
1445 if ( self::is_module_active( 'product_badges' ) && 'rtsb_yes' === $text ) {
1446 do_action( 'rtsb/modules/product_badges/frontend/display' );
1447
1448 return;
1449 }
1450
1451 if ( empty( $text ) ) {
1452 return;
1453 }
1454 ob_start();
1455 ?>
1456
1457 <ul class="rtsb-promotion-list">
1458 <li class="rtsb-promotion-list-item">
1459 <span class="rtsb-tag-<?php echo ! empty( $class ) ? esc_attr( $class ) : ''; ?>"><?php echo esc_html( $text ); ?></span>
1460 </li>
1461 </ul>
1462
1463 <?php
1464 self::print_html( ob_get_clean() );
1465 }
1466
1467 /**
1468 * Categories HTML
1469 *
1470 * @param int $id Product ID.
1471 * @param string $class Custom class.
1472 *
1473 * @return void|string
1474 */
1475 public static function get_categories_list( $id, $class = 'rtsb-category-outline' ) {
1476 if ( empty( $id ) ) {
1477 return '';
1478 }
1479
1480 ob_start();
1481 ?>
1482
1483 <ul class="rtsb-category-list <?php echo esc_attr( $class ); ?>">
1484 <?php
1485 self::print_html(
1486 wc_get_product_category_list(
1487 $id,
1488 '</li><li class="rtsb-category-list-item">',
1489 '<li class="rtsb-category-list-item">',
1490 '</li>'
1491 )
1492 );
1493 ?>
1494 </ul>
1495
1496 <?php
1497 self::print_html( ob_get_clean() );
1498 }
1499
1500 /**
1501 * Get Featured Image HTML.
1502 *
1503 * @param string $type Image type.
1504 * @param int $post_id Post ID.
1505 * @param string $f_img_size Image size.
1506 * @param null $default_img_id Default image ID.
1507 * @param array $custom_img_size Custom image size.
1508 * @param bool $lazy Lazy load check.
1509 * @param bool $hover Hover image.
1510 * @param bool $gallery Gallery image.
1511 * @param bool $custom_image_id Custom category image ID.
1512 *
1513 * @return string|null
1514 */
1515 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 ) {
1516 $img_html = null;
1517 $attachment_id = null;
1518 $c_size = false;
1519 $hover_class = '';
1520 $post_title = '';
1521
1522 if ( 'rtsb_custom' === $f_img_size ) {
1523 $f_img_size = 'full';
1524 $c_size = true;
1525 }
1526
1527 if ( ! rtsb()->has_pro() ) {
1528 $gallery = false;
1529 }
1530
1531 if ( $hover ) {
1532 $a_id = $post_id;
1533 $hover_class = ' rtsb-img-hover';
1534 } elseif ( $gallery ) {
1535 $a_id = $post_id;
1536 } else {
1537 if ( 'product' === $type ) {
1538 $a_id = get_post_thumbnail_id( $post_id );
1539 $post_title = get_the_title( $post_id );
1540 } elseif ( 'category' === $type ) {
1541 $a_id = $custom_image_id ? $custom_image_id : get_term_meta( $post_id, 'thumbnail_id', true );
1542 $post_title = get_term( $post_id )->name;
1543 } else {
1544 $a_id = $default_img_id;
1545 }
1546 }
1547
1548 $img_alt = trim( wp_strip_all_tags( get_post_meta( $a_id, '_wp_attachment_image_alt', true ) ) );
1549 $alt_tag = ! empty( $img_alt ) ? $img_alt : wp_strip_all_tags( $post_title );
1550 $lazy_class = $lazy ? ' swiper-lazy' : '';
1551 $attr = [
1552 'class' => 'img-responsive rtsb-product-image' . $lazy_class . $hover_class,
1553 'alt' => $alt_tag,
1554 ];
1555
1556 if ( $a_id ) {
1557 $img_html = wp_get_attachment_image( $a_id, $f_img_size, false, $attr );
1558 $attachment_id = $a_id;
1559 }
1560
1561 if ( ! $img_html && $default_img_id ) {
1562 $img_html = wp_get_attachment_image( $default_img_id, $f_img_size, false, $attr );
1563 $attachment_id = $default_img_id;
1564 }
1565
1566 if ( $img_html && $c_size ) {
1567 preg_match( '@src="([^"]+)"@', $img_html, $match );
1568 $img_src = array_pop( $match );
1569 $w = ! empty( $custom_img_size['width'] ) ? absint( $custom_img_size['width'] ) : null;
1570 $h = ! empty( $custom_img_size['height'] ) ? absint( $custom_img_size['height'] ) : null;
1571 $c = ! empty( $custom_img_size['crop'] ) && 'soft' === $custom_img_size['crop'] ? false : true;
1572
1573 if ( $w && $h ) {
1574 $image = self::image_resize( $img_src, $w, $h, $c, false );
1575
1576 if ( ! empty( $image ) ) {
1577 [ $src, $width, $height ] = $image;
1578
1579 $hwstring = image_hwstring( $width, $height );
1580 $attachment = get_post( $attachment_id );
1581 $attr = apply_filters( 'wp_get_attachment_image_attributes', $attr, $attachment, $f_img_size );
1582
1583 if ( $lazy ) {
1584 $attr['data-src'] = $src;
1585 } else {
1586 $attr['src'] = $src;
1587 }
1588
1589 $attr = array_map( 'esc_attr', $attr );
1590 $img_html = rtrim( "<img $hwstring" );
1591
1592 foreach ( $attr as $name => $value ) {
1593 $img_html .= " $name=" . '"' . $value . '"';
1594 }
1595
1596 $img_html .= ' />';
1597 }
1598 }
1599 }
1600
1601 if ( ! $img_html ) {
1602 $hwstring = image_hwstring( 160, 160 );
1603 $attr = isset( $attr['src'] ) ? apply_filters( 'wp_get_attachment_image_attributes', $attr, false, $f_img_size ) : [];
1604 $attr['class'] = 'default-img';
1605 $attr['src'] = esc_url( rtsb()->get_assets_uri( 'images/demo.png' ) );
1606 $attr['alt'] = esc_html__( 'Default Image', 'shopbuilder' );
1607 $img_html = rtrim( "<img $hwstring" );
1608
1609 foreach ( $attr as $name => $value ) {
1610 $img_html .= " $name=" . '"' . $value . '"';
1611 }
1612
1613 $img_html .= ' />';
1614 }
1615
1616 if ( $lazy ) {
1617 $img_html = $img_html . '<div class="swiper-lazy-preloader swiper-lazy-preloader"></div>';
1618 }
1619
1620 return $img_html;
1621 }
1622
1623 /**
1624 * Call the Image resize model for resize function
1625 *
1626 * @param string $url URL.
1627 * @param int $width Width.
1628 * @param int $height Height.
1629 * @param string $crop Crop.
1630 * @param bool|true $single Single.
1631 * @param bool|false $upscale Upscale.
1632 *
1633 * @return array|bool|string
1634 */
1635 public static function image_resize( $url, $width = null, $height = null, $crop = null, $single = true, $upscale = false ) {
1636 $rtResize = new ReSizer();
1637
1638 return $rtResize->process( $url, $width, $height, $crop, $single, $upscale );
1639 }
1640
1641 /**
1642 * Get Product Image
1643 *
1644 * @param string $f_image Featured Image.
1645 * @param string $h_image Hover Image.
1646 *
1647 * @return void
1648 */
1649 public static function get_product_image( $f_image, $h_image = null ) {
1650 if ( empty( $f_image ) ) {
1651 return;
1652 }
1653
1654 echo wp_kses( $f_image, self::allowedHtml( 'image' ) );
1655
1656 if ( ! empty( $h_image ) ) {
1657 echo wp_kses( $h_image, self::allowedHtml( 'image' ) );
1658 }
1659 }
1660
1661 /**
1662 * Post Custom Field value.
1663 *
1664 * @param int $post_id Post id.
1665 * @param string $field_key Custom Field Key.
1666 * @param string $field_fallback FallBack text.
1667 *
1668 * @return string|void
1669 */
1670 public static function get_post_custom_field_value( $post_id, $field_key = '', $field_fallback = '' ) {
1671 if ( ! $post_id || ! $field_key ) {
1672 return;
1673 }
1674 $field_value = get_post_meta( $post_id, $field_key, true );
1675 if ( empty( $field_value ) ) {
1676 $field_value = ! empty( $field_fallback ) ? $field_fallback : $field_value;
1677 }
1678 $field_value = apply_filters( 'rtsb/get_post_custom_field_value/' . $field_key, $field_value, $field_key );
1679
1680 return sprintf( '<span class="rtsb-woo-custom-field">%s</span>', $field_value );
1681 }
1682
1683 /**
1684 * Elementor Icon
1685 *
1686 * @param array $control Elementor Control array.
1687 * @param string $class Custom class.
1688 * @param string $builder Builder name.
1689 *
1690 * @return string
1691 */
1692 public static function icons_manager( $control, $class = '', $builder = 'elementor' ): string {
1693 if ( empty( $control['value'] ) ) {
1694 return '';
1695 }
1696 if ( is_array( $control['value'] ) ) {
1697 $cache_key = 'icons_managet_' . str_replace( ' ', '', md5( serialize( $control['value'] ) ) );
1698 } else {
1699 $cache_key = 'icons_managet_' . str_replace( ' ', '', $control['value'] );
1700 }
1701 if ( isset( self::$cache[ $cache_key ] ) ) {
1702 return self::$cache[ $cache_key ];
1703 }
1704
1705 $attributes = [
1706 'aria-hidden' => 'true',
1707 ];
1708
1709 if ( ! empty( $class ) ) {
1710 $attributes['class'] = esc_attr( $class );
1711 }
1712
1713 ob_start();
1714
1715 if ( defined( 'ELEMENTOR_VERSION' ) && ! empty( $control ) && 'elementor' === $builder ) {
1716 Icons_Manager::render_icon( $control, $attributes );
1717 }
1718
1719 $icons = ob_get_clean();
1720 self::$cache[ $cache_key ] = $icons;
1721 return $icons;
1722 }
1723
1724 /**
1725 * Get product swatches.
1726 *
1727 * @param string $type Swatch type.
1728 *
1729 * @return void
1730 */
1731 public static function get_product_swatches( $type ) {
1732 ?>
1733 <div class="rtsb-swatches <?php echo esc_attr( $type ); ?>-layout">
1734 <?php
1735 do_action( 'rtwpvs_show_archive_variation' );
1736 ?>
1737 </div>
1738 <?php
1739 }
1740
1741 /**
1742 * Get sale badge
1743 *
1744 * @param string $type Badge type.
1745 * @param string $text Badge text.
1746 * @param string $out_of_stock_text Out of stock text.
1747 *
1748 * @return string
1749 */
1750 public static function get_sale_badge( $type, $text, $out_of_stock_text ) {
1751 global $product;
1752
1753 if ( ! $product->is_in_stock() ) {
1754 return $out_of_stock_text;
1755 }
1756
1757 if ( ! $product->is_on_sale() ) {
1758 return '';
1759 }
1760
1761 $badge_text = '';
1762 $percentage = self::calculate_sale_percentage( $product );
1763
1764 if ( $percentage > 0 ) {
1765 $badge_text = '-' . round( $percentage ) . '%';
1766 }
1767
1768 if ( 'text' === $type ) {
1769 $badge_text = $text;
1770 }
1771
1772 return $badge_text;
1773 }
1774
1775 /**
1776 * Get sale badge
1777 *
1778 * @param object $product Product Object.
1779 * @param string $type Badge type.
1780 * @param string $text Badge text.
1781 * @param string $out_of_stock_text Out of stock text.
1782 *
1783 * @return string
1784 */
1785 public static function get_promo_badge( $product, $type, $text, $out_of_stock_text ) {
1786 $disable_badges = self::get_option( 'general', 'guest_user', 'hide_badges', '' );
1787 $badges_visibility = rtsb()->has_pro() && ! is_user_logged_in() && $disable_badges;
1788
1789 if ( $badges_visibility ) {
1790 return '';
1791 }
1792
1793 if ( is_null( $product ) ) {
1794 global $product;
1795 }
1796
1797 if ( ! $product instanceof WC_Product ) {
1798 return '';
1799 }
1800
1801 if ( ! $product->is_in_stock() ) {
1802 return $out_of_stock_text;
1803 }
1804
1805 if ( ! $product->is_on_sale() ) {
1806 return '';
1807 }
1808
1809 $badge_text = '';
1810 $percentage = self::calculate_sale_percentage( $product );
1811
1812 if ( $percentage > 0 ) {
1813 $badge_text = '-' . round( $percentage ) . '%';
1814 }
1815
1816 if ( 'text' === $type ) {
1817 $badge_text = $text;
1818 }
1819
1820 return $badge_text;
1821 }
1822
1823 /**
1824 * Calculate Sale Percentage
1825 *
1826 * @param object $product Product object.
1827 *
1828 * @return float|int|string
1829 */
1830 public static function calculate_sale_percentage( $product = null ) {
1831 if ( is_null( $product ) ) {
1832 global $product;
1833 }
1834
1835 if ( ! $product instanceof WC_Product ) {
1836 return '';
1837 }
1838
1839 if ( ! $product->is_on_sale() ) {
1840 return '';
1841 }
1842
1843 $percentage = null;
1844 $max_percentage = '';
1845
1846 if ( $product->is_type( 'simple' ) ) {
1847 $max_percentage = $product->get_sale_price() ? ( ( $product->get_regular_price() - $product->get_sale_price() ) / $product->get_regular_price() ) * 100 : 0;
1848 } elseif ( $product->is_type( 'variable' ) ) {
1849 $max_percentage = 0;
1850
1851 foreach ( $product->get_children() as $child_id ) {
1852
1853 $variation = wc_get_product( $child_id );
1854
1855 $price = $variation->get_regular_price();
1856 $sale = $variation->get_sale_price();
1857
1858 if ( 0 !== $price && ! empty( $sale ) ) {
1859 $percentage = ( $price - $sale ) / $price * 100;
1860 }
1861
1862 if ( $percentage > $max_percentage ) {
1863 $max_percentage = $percentage;
1864 }
1865 }
1866 }
1867
1868 if ( $max_percentage > 0 ) {
1869 return round( $max_percentage );
1870 }
1871
1872 return 0;
1873 }
1874
1875 /**
1876 * Pagination
1877 *
1878 * @param string $pages Pages.
1879 * @param integer $range Range.
1880 * @param boolean $ajax Ajax.
1881 *
1882 * @return string
1883 */
1884 public static function custom_pagination( $pages = '', $range = 4, $ajax = false ) {
1885 $html = null;
1886 $visible_range = apply_filters( 'rtsb/elements/pagination/visible_range', ( $range * 2 ) + 1 );
1887
1888 global $paged;
1889
1890 if ( is_front_page() ) {
1891 $paged = ( get_query_var( 'page' ) ) ? get_query_var( 'page' ) : 1;
1892 } else {
1893 $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
1894 }
1895
1896 if ( empty( $paged ) ) {
1897 $paged = 1;
1898 }
1899
1900 if ( '' === $pages ) {
1901 global $wp_query;
1902
1903 $pages = $wp_query->max_num_pages;
1904
1905 if ( ! $pages ) {
1906 $pages = 1;
1907 }
1908 }
1909
1910 $ajaxClass = null;
1911 $dataAttr = null;
1912
1913 if ( $ajax ) {
1914 $ajaxClass = ' rtsb-pagination-ajax';
1915 $dataAttr = "data-paged='1'";
1916 $dataAttr .= ' data-visible-range="' . esc_attr( $visible_range ) . '"';
1917 }
1918
1919 if ( 1 !== $pages ) {
1920 $html .= '<div class="rtsb-pagination' . $ajaxClass . '" ' . $dataAttr . '>';
1921 $html .= '<ul class="pagination-list">';
1922
1923 if ( $paged > 2 && $paged > $visible_range + 1 && $visible_range < $pages ) {
1924 $html .= "<li><a data-paged='1' href='" . get_pagenum_link( 1 ) . "' aria-label='First'>&laquo;</a></li>";
1925 }
1926
1927 if ( $paged > 1 && $visible_range < $pages ) {
1928 $p = $paged - 1;
1929 $html .= "<li><a data-paged='{$p}' href='" . get_pagenum_link( $p ) . "' aria-label='Previous'>&lsaquo;</a></li>";
1930 }
1931
1932 for ( $i = 1; $i <= $pages; $i++ ) {
1933 if ( 1 != $pages && ( ! ( $i >= $paged + $visible_range + 1 || $i <= $paged - $visible_range - 1 ) || $pages <= $visible_range ) ) {
1934 $html .= ( $paged == $i ) ? '<li class="active"><span>' . $i . '</span></li>' : "<li><a data-paged='{$i}' href='" . get_pagenum_link( $i ) . "'>" . $i . '</a></li>';
1935 }
1936 }
1937
1938 if ( $paged < $pages && $visible_range < $pages ) {
1939 $p = $paged + 1;
1940 $html .= "<li><a data-paged='{$p}' href=\"" . get_pagenum_link( $paged + 1 ) . "\" aria-label='Next'>&rsaquo;</a></li>";
1941 }
1942
1943 if ( $paged < $pages - 1 && $paged + $range - 1 < $pages && $visible_range < $pages ) {
1944 $html .= "<li><a data-paged='{$pages}' href='" . get_pagenum_link( $pages ) . "' aria-label='Last'>&raquo;</a></li>";
1945 }
1946
1947 $html .= '</ul>';
1948 $html .= '</div>';
1949 }
1950
1951 return $html;
1952 }
1953
1954 /**
1955 * Action Buttons HTMl
1956 *
1957 * @param array $items Items.
1958 * @param array $ajax_cart Ajax cart HTML.
1959 * @param string $preset Button preset.
1960 * @param array $position Position.
1961 * @param string $placement Placement.
1962 *
1963 * @return void|string
1964 */
1965 public static function get_formatted_action_buttons( $items, $ajax_cart = '', $preset = 'preset1', $position = 'above', $placement = 'top' ) {
1966 if ( empty( $items ) ) {
1967 return;
1968 }
1969
1970 $html = '';
1971 $class = '';
1972 $args = [ $items, $ajax_cart, $preset, $position, $placement ];
1973
1974 if ( ( 'top' === $placement && 'after' === $position ) || ( 'bottom' === $placement && 'above' === $position ) ) {
1975 return apply_filters( 'rtsb/elements/elementor/formatted_action_buttons', $html, $args );
1976 }
1977
1978 if ( 'preset2' === $preset ) {
1979 $class = 'rtsb-action-buttons-vertical vertical-delay-effect ' . $preset;
1980 } elseif ( 'preset4' === $preset ) {
1981 $class = 'rtsb-action-buttons-vertical rtsb-action-buttons-vertical-left vertical-delay-effect ' . $preset;
1982 } elseif ( 'preset1' === $preset || 'preset3' === $preset ) {
1983 $class = 'rtsb-action-buttons-cart-box-width-auto horizontal-floating-btn ' . $preset;
1984 }
1985
1986 if ( 'after' === $position && 'preset1' === $preset ) {
1987 $class .= ' after-content';
1988 }
1989
1990 if ( 'preset3' === $preset ) {
1991 $html .= '<div class="rtsb-action-buttons top-part ' . esc_attr( $preset ) . '">';
1992 $html .= '<ul class="rtsb-action-button-list">';
1993
1994 ob_start();
1995 /**
1996 * Additional formatted action buttons hook.
1997 */
1998 do_action( 'rtsb/elements/elementor/additional_action_buttons', $items );
1999 $html .= ob_get_clean();
2000
2001 $html .= self::get_action_button_by_type( $items, 'wishlist' );
2002 $html .= self::get_action_button_by_type( $items, 'compare' );
2003 $html .= self::get_action_button_by_type( $items, 'quick_view' );
2004 $html .= '</ul>';
2005 $html .= '</div>';
2006 $html .= '<div class="rtsb-action-buttons bottom-part ' . esc_attr( $preset ) . '">';
2007 $html .= '<ul class="rtsb-action-button-list">';
2008 $html .= self::get_action_button_by_type( $items, 'add_to_cart', $ajax_cart );
2009 $html .= '</ul>';
2010 $html .= '</div>';
2011 } elseif ( 'preset1' === $preset || 'preset2' === $preset || 'preset4' === $preset ) {
2012 $html .= '<div class="rtsb-action-buttons ' . esc_attr( $class ) . '">';
2013 $html .= '<ul class="rtsb-action-button-list">';
2014 $html .= self::get_action_button_by_type( $items, 'add_to_cart', $ajax_cart );
2015
2016 ob_start();
2017 /**
2018 * Additional formatted action buttons hook.
2019 */
2020 do_action( 'rtsb/elements/elementor/additional_action_buttons', $items );
2021 $html .= ob_get_clean();
2022
2023 $html .= self::get_action_button_by_type( $items, 'wishlist' );
2024 $html .= self::get_action_button_by_type( $items, 'compare' );
2025 $html .= self::get_action_button_by_type( $items, 'quick_view' );
2026 $html .= '</ul>';
2027 $html .= '</div>';
2028 }
2029
2030 return apply_filters( 'rtsb/elements/elementor/formatted_action_buttons', $html, $args );
2031 }
2032
2033 /**
2034 * Get Action Button HTML
2035 *
2036 * @param array $items Items.
2037 * @param string $type Button type.
2038 * @param string $cart_html Ajax cart HTML.
2039 * @param string $wrapper Wrapper tag.
2040 *
2041 * @return void|string
2042 */
2043 public static function get_action_button_by_type( $items, $type, $cart_html = '', $wrapper = 'li' ) {
2044 if ( ! in_array( $type, $items, true ) ) {
2045 return;
2046 }
2047
2048 $html = '';
2049 $class = 'rtsb-action-button-item';
2050
2051 if ( 'add_to_cart' === $type ) {
2052 $class .= ' rtsb-cart' . ( empty( $cart_html ) ? esc_attr( ' no-cart-button' ) : '' );
2053 } else {
2054 $class .= ' rtsb-' . esc_attr( str_replace( '_', '-', $type ) );
2055 }
2056
2057 $html .= '<' . esc_attr( $wrapper ) . ' class="' . esc_attr( $class ) . '">';
2058
2059 if ( ( 'add_to_cart' === $type ) && ( ! empty( $cart_html ) ) ) {
2060 $html .= $cart_html;
2061 } else {
2062 $html .= shortcode_exists( 'rtsb_' . $type . '_button' ) ? do_shortcode( '[rtsb_' . $type . '_button]' ) : null;
2063 }
2064
2065 $html .= '</' . esc_attr( $wrapper ) . '>';
2066
2067 return apply_filters( 'rtsb/elements/elementor/get_action_button_by_type', $html );
2068 }
2069
2070 /**
2071 * Social Share Platforms.
2072 *
2073 * @return mixed|null
2074 */
2075 public static function social_share_platforms_list() {
2076 return apply_filters(
2077 'rtsb/settings/social_share/platforms',
2078 [
2079 [
2080 'value' => 'facebook',
2081 'label' => esc_html__( 'Facebook', 'shopbuilder' ),
2082 ],
2083 [
2084 'value' => 'twitter',
2085 'label' => esc_html__( 'Twitter', 'shopbuilder' ),
2086 ],
2087 [
2088 'value' => 'linkedin',
2089 'label' => esc_html__( 'Linkedin', 'shopbuilder' ),
2090 ],
2091 [
2092 'value' => 'pinterest',
2093 'label' => esc_html__( 'Pinterest', 'shopbuilder' ),
2094 ],
2095 [
2096 'value' => 'skype',
2097 'label' => esc_html__( 'Skype', 'shopbuilder' ),
2098 ],
2099 [
2100 'value' => 'whatsapp',
2101 'label' => esc_html__( 'Whatsapp', 'shopbuilder' ),
2102 ],
2103 [
2104 'value' => 'reddit',
2105 'label' => esc_html__( 'Reddit', 'shopbuilder' ),
2106 ],
2107 [
2108 'value' => 'telegram',
2109 'label' => esc_html__( 'Telegram', 'shopbuilder' ),
2110 ],
2111 ]
2112 );
2113 }
2114
2115 /**
2116 * Get Social Share link HTML.
2117 *
2118 * @param int $id Post ID.
2119 * @param array $types Preset type.
2120 * @param string $preset Style type.
2121 * @param boolean $show_icon Show icon.
2122 * @param boolean $show_text Show text.
2123 *
2124 * @return string
2125 */
2126 public static function get_social_share_html( int $id, array $types, string $preset = 'default', $show_icon = true, $show_text = true ) {
2127 $attr = [ 'postid' => $id ];
2128 $output = '';
2129
2130 if ( empty( $types ) ) {
2131 return $output;
2132 }
2133
2134 foreach ( $types as $type ) {
2135 $link = [];
2136 $link['type'] = $type['share_items'];
2137 $link['class'] = '';
2138 $link['img'] = apply_filters( 'rtsb/elements/share/default_img', '', $id, $link );
2139
2140 if ( 'site' === $id ) {
2141 $link['url'] = home_url();
2142 $link['title'] = wp_strip_all_tags( get_bloginfo( 'name' ) );
2143 } elseif ( 0 === strpos( $id, 'http' ) ) {
2144 $link['url'] = $id;
2145 $link['title'] = '';
2146 } else {
2147 $link['url'] = get_permalink( $id );
2148 $link['title'] = wp_strip_all_tags( get_the_title( $id ) );
2149
2150 if ( has_post_thumbnail( $id ) ) {
2151 $link['img'] = wp_get_attachment_image_url( get_post_thumbnail_id( $id ), 'full' );
2152 }
2153
2154 $link['img'] = apply_filters( 'rtsb/elements/share/single_img', $link['img'], $id, $link );
2155 }
2156
2157 $link['url'] = apply_filters( 'rtsb/elements/share/url', $link['url'], $link );
2158
2159 switch ( $type['share_items'] ) {
2160 case 'facebook':
2161 $link['link'] = esc_url( 'https://www.facebook.com/sharer/sharer.php?u=' . $link['url'] . '&display=popup&ref=plugin&src=share_button' );
2162 $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>';
2163 $link['attr_title'] = esc_html__( 'Share on Facebook', 'shopbuilder' );
2164 $link['social_network'] = 'Facebook';
2165 $link['social_action'] = 'Share';
2166 break;
2167 case 'twitter':
2168 $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'] );
2169 $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>';
2170 $link['attr_title'] = esc_html__( 'Share on Twitter', 'shopbuilder' );
2171 $link['social_network'] = 'Twitter';
2172 $link['social_action'] = 'Tweet';
2173 break;
2174 case 'pinterest':
2175 $link['link'] = esc_url( 'https://pinterest.com/pin/create/button/?url=' . $link['url'] . '&media=' . $link['img'] . '&description=' . $link['title'] );
2176 $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>';
2177 $link['attr_title'] = esc_html__( 'Share on Pinterest', 'shopbuilder' );
2178 $link['social_network'] = 'Pinterest';
2179 $link['social_action'] = 'Pin';
2180 break;
2181 case 'linkedin':
2182 $link['link'] = esc_url( 'https://www.linkedin.com/shareArticle?url=' . $link['url'] . '&title=' . $link['title'] );
2183 $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>';
2184 $link['attr_title'] = esc_html__( 'Share on LinkedIn', 'shopbuilder' );
2185 $link['social_network'] = 'LinkedIn';
2186 $link['social_action'] = 'Share';
2187 break;
2188 case 'skype':
2189 $link['link'] = esc_url( 'https://web.skype.com/share?url=' . $link['url'] );
2190 $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>';
2191 $link['attr_title'] = esc_html__( 'Share on Skype', 'shopbuilder' );
2192 $link['social_network'] = 'Skype';
2193 $link['social_action'] = 'Skype';
2194 break;
2195 case 'whatsapp':
2196 $link['link'] = esc_url( 'https://wa.me/?text=' . $link['title'] . ' ' . $link['url'] );
2197 $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>';
2198 $link['attr_title'] = esc_html__( 'Share on Whatsapp', 'shopbuilder' );
2199 $link['social_network'] = 'Whatsapp';
2200 $link['social_action'] = 'Share';
2201 break;
2202 case 'reddit':
2203 $link['link'] = esc_url( 'https://reddit.com/submit?url=' . $link['url'] . '&title=' . $link['title'] );
2204 $link['icon'] = '<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><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>';
2205 $link['attr_title'] = esc_html__( 'Share on Reddit', 'shopbuilder' );
2206 $link['social_network'] = 'Reddit';
2207 $link['social_action'] = 'Share';
2208 break;
2209 case 'telegram':
2210 $link['link'] = esc_url( 'https://telegram.me/share/url?text=' . $link['title'] . '&url=' . $link['url'] );
2211 $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>';
2212 $link['attr_title'] = esc_html__( 'Share on Telegram', 'shopbuilder' );
2213 $link['social_network'] = 'Telegram';
2214 $link['social_action'] = 'Share';
2215 break;
2216 }
2217
2218 $link['label'] = $type['share_text'];
2219 $link['target'] = '_blank';
2220 $link['rel'] = 'nofollow noopener noreferrer';
2221
2222 $data = '';
2223 $link = apply_filters( 'rtsb/elements/share/share_link', $link, $id, $preset );
2224 $icon = apply_filters( 'rtsb/elements/share/share_icon', $link['icon'], $preset );
2225 $target = ! empty( $link['target'] ) ? ' target="' . esc_attr( $link['target'] ) . '" ' : '';
2226 $rel = ! empty( $link['rel'] ) ? ' rel="' . esc_attr( $link['rel'] ) . '" ' : '';
2227 $attr_title = ! empty( $link['attr_title'] ) ? ' title="' . esc_attr( $link['attr_title'] ) . '" ' : '';
2228 $elements = [];
2229
2230 // Add classes.
2231 $css_classes = [
2232 'rtsb-share-btn',
2233 sanitize_html_class( $link['type'] ),
2234 ];
2235 $css_classes = array_merge( $css_classes, explode( ' ', $link['class'] ) );
2236 $css_classes = array_map( 'sanitize_html_class', $css_classes );
2237 $css_classes = implode( ' ', array_filter( $css_classes ) );
2238
2239 unset( $attr['pin-do'], $attr['action'] );
2240
2241 if ( 'pinterest' === $type['share_items'] ) {
2242 $attr['pin-do'] = 'none';
2243 }
2244
2245 if ( 'whatsapp' === $type['share_items'] ) {
2246 $attr['action'] = 'share/whatsapp/share';
2247 }
2248
2249 $attr = apply_filters( 'rtsb/elements/share/link_data', $attr, $link, $id );
2250
2251 if ( ! empty( $attr ) ) {
2252 foreach ( $attr as $key => $val ) {
2253 $data .= ' data-' . sanitize_html_class( $key ) . '="' . esc_attr( $val ) . '"';
2254 }
2255 }
2256
2257 $additional_attr = apply_filters( 'rtsb/elements/share/additional_attr', [], $link, $id, $preset );
2258
2259 if ( ! empty( $additional_attr ) ) {
2260 $attr_output = join( ' ', $additional_attr );
2261
2262 if ( ! empty( $data ) ) {
2263 $attr_output = ' ' . $attr_output;
2264 }
2265
2266 $data .= $attr_output;
2267 }
2268
2269 $elements['wrapper_start'] = sprintf(
2270 '<li class="rtsb-share-item"><a href="%s"%s%s%s class="%s"%s>',
2271 ! empty( $link['link'] ) ? esc_attr( $link['link'] ) : '',
2272 $attr_title,
2273 $target,
2274 $rel,
2275 $css_classes,
2276 $data
2277 );
2278 $elements['wrapper_end'] = '</a></li>';
2279
2280 $elements['icon'] = $show_icon ? '<span class="rtsb-share-icon">' . ( ! empty( $icon ) ? $icon : null ) . '</span>' : null;
2281 $elements['label'] = $show_text && ! empty( $link['label'] ) ? '<span class="rtsb-share-label">' . $link['label'] . '</span>' : null;
2282 $elements['icon_label'] = '<span class="rtsb-share-icon-label">' . $elements['icon'] . $elements['label'] . '</span>';
2283 $elements = apply_filters( 'rtsb/elements/share/output_elements', $elements, $link, $id );
2284
2285 $output .= $elements['wrapper_start'] . $elements['icon_label'] . $elements['wrapper_end'];
2286 }
2287
2288 return apply_filters( 'rtsb/elements/share/list_output', $output );
2289 }
2290
2291 /**
2292 * Social Share Platforms.
2293 *
2294 * @return mixed|null
2295 */
2296 public static function is_module_active( $module ) {
2297 $modulelist = ModuleList::instance()->get_data();
2298 if ( ! empty( $modulelist[ $module ]['active'] ) ) {
2299 return true;
2300 }
2301 }
2302
2303 /***
2304 * Save Settings data
2305 *
2306 * @param $section_id
2307 * @param $block_id
2308 * @param $rawOptions
2309 *
2310 * @return array
2311 */
2312 public static function set_options( $section_id = '', $block_id = '', $rawOptions = [] ) {
2313 $section_id = ! empty( $section_id ) ? sanitize_text_field( wp_unslash( $section_id ) ) : '';
2314 $block_id = ! empty( $block_id ) ? sanitize_text_field( wp_unslash( $block_id ) ) : '';
2315 $rawOptions = ! empty( $rawOptions ) ? $rawOptions : [];
2316 $results = [
2317 'status' => true,
2318 'message' => '',
2319 ];
2320 if ( ! $section_id || ! $block_id ) {
2321 $results['status'] = false;
2322 $results['message'] = esc_html__( 'Section , block or options may be empty', 'shopbuilder' );
2323
2324 return $results;
2325 }
2326 $sections = Settings::instance()->get_sections();
2327 if ( empty( $sections[ $section_id ] ) || empty( $sections[ $section_id ]['list'][ $block_id ] ) ) {
2328 $results['status'] = false;
2329 $results['message'] = esc_html__( 'No section or block found with given data', 'shopbuilder' );
2330
2331 return $results;
2332 }
2333
2334 $options = DataModel::source()->get_option( $section_id, [], false );
2335 $changed = false;
2336 $fields = [];
2337 if ( isset( $sections[ $section_id ]['list'][ $block_id ]['fields'] ) && ! empty( $sections[ $section_id ]['list'][ $block_id ]['fields'] ) ) {
2338 $fields = $sections[ $section_id ]['list'][ $block_id ]['fields'];
2339 }
2340
2341 if ( empty( $fields ) ) {
2342 if ( isset( $rawOptions['active'] ) ) {
2343 $changed = true;
2344 $options[ $block_id ]['active'] = 'on' === $rawOptions['active'] ? 'on' : '';
2345 }
2346 } else {
2347 foreach ( $rawOptions as $raw_option_key => $raw_value ) {
2348 if ( $raw_option_key === 'active' ) {
2349 $changed = true;
2350 $options[ $block_id ]['active'] = $sections[ $section_id ]['list'][ $block_id ]['active'] = 'on' === $raw_value ? 'on' : '';
2351 } else {
2352 if ( isset( $fields[ $raw_option_key ] ) ) {
2353 $field = $fields[ $raw_option_key ];
2354 if ( $field['type'] === 'switch' ) {
2355 $value = 'on' === $raw_value ? 'on' : '';
2356 } elseif ( 'repeaters' === $field['type'] ) {
2357 $the_value = [];
2358 $rep_title = [];
2359 if ( ! empty( $raw_value ) && is_array( $raw_value ) ) {
2360 foreach ( $raw_value as $key => $value ) {
2361 if ( is_string( $value ) ) {
2362 $the_value_decoded = json_decode( stripslashes_deep( $value ) );
2363 } else {
2364 $the_value_decoded = $value;
2365 }
2366 $cr = $the_value_decoded->title ?? '';
2367 if ( in_array( $cr, $rep_title, true ) ) {
2368 continue;
2369 }
2370 $rep_title[] = $cr;
2371 $the_value[] = $the_value_decoded;
2372 }
2373 } elseif ( ! empty( $raw_value ) && is_string( $raw_value ) ) {
2374 $the_value = $raw_value;
2375 }
2376 $value = wp_json_encode( $the_value );
2377 } elseif ( in_array( $field['type'], [ 'product_addons_special_settings', 'checkout_fields' ] ) ) {
2378 $manual_field_value = [];
2379 if ( is_array( $raw_value ) ) {
2380 foreach ( $raw_value as $key => $value ) {
2381 $manual_field_value[] = json_decode( stripslashes( $value ), true );
2382 }
2383 $value = wp_json_encode( $manual_field_value );
2384 } elseif ( is_string( $raw_value ) ) {
2385 $value = $raw_value;
2386 }
2387 } else {
2388 if ( ! empty( $field['multiple'] ) || in_array( $field['type'], [ 'checkbox', 'search_and_multi_select' ] ) ) {
2389 if ( isset( $raw_value ) && is_array( $raw_value ) ) {
2390 if ( ! empty( $field['sanitize_fn'] ) && is_callable( $field['sanitize_fn'] ) ) {
2391 $value = array_map( $field['sanitize_fn'], $raw_value );
2392 } else {
2393 $value = array_map( 'sanitize_text_field', $raw_value );
2394 }
2395 } else {
2396 $value = [];
2397 }
2398 } else {
2399 if ( ! empty( $field['sanitize_fn'] ) ) {
2400 if ( is_callable( $field['sanitize_fn'] ) ) {
2401 $value = $field['sanitize_fn']( $raw_value );
2402 } elseif ( 'pass_all' === $field['sanitize_fn'] ) {
2403 $value = $raw_value;
2404 } else {
2405 $value = $field['sanitize_fn']( $raw_value );
2406 }
2407 } else {
2408 $value = sanitize_text_field( $raw_value );
2409 }
2410 }
2411 }
2412 $options[ $block_id ][ $raw_option_key ] = $sections[ $section_id ]['list'][ $block_id ]['fields'][ $raw_option_key ]['value'] = $value ?? null;
2413 $changed = true;
2414 }
2415 }
2416 }
2417 }
2418 if ( ! $changed ) {
2419 $results['status'] = false;
2420 $results['message'] = esc_html__( 'No changes found for update', 'shopbuilder' );
2421
2422 return $results;
2423 }
2424
2425 DataModel::source()->set_option( $section_id, $options );
2426
2427 $results['status'] = true;
2428 $results['message'] = esc_html__( 'Successfully Saved', 'shopbuilder' );
2429 $results['sections'] = $sections;
2430
2431 return $results;
2432 }
2433
2434 /***
2435 * @param $meta_key
2436 * @param $meta_value
2437 *
2438 * @return mixed|void
2439 *
2440 *
2441 * public static function get_post_id_by_meta_key_and_value( $meta_key, $meta_value ) {
2442 * if( ! $meta_key || ! $meta_value ){
2443 * return;
2444 * }
2445 * global $wpdb;
2446 * $prepare_guery = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '%s' and meta_value = '%d'", $meta_key, $meta_value );
2447 * $the_products = $wpdb->get_col( $prepare_guery );
2448 * if( count( $the_products ) > 0 ){
2449 * return $the_products[0];
2450 * }
2451 * return;
2452 * }
2453 */
2454 public static function count_products_by_taxonomies( $terms, $taxonomy = 'product_cat' ) {
2455 if ( empty( $terms ) || ! is_array( $terms ) ) {
2456 return;
2457 }
2458
2459 $args = [
2460 'limit' => -1,
2461 'return' => 'ids',
2462 ];
2463
2464 if ( 'product_cat' === $taxonomy ) {
2465 $args['product_category_id'] = $terms;
2466 } else {
2467 $args['product_tag_id'] = $terms;
2468 }
2469
2470 $query = new WC_Product_Query( $args );
2471 return ! empty( $query->get_products() ) ? count( $query->get_products() ) : 0;
2472 }
2473
2474 /**
2475 * Check if product filters widget has ajax.
2476 *
2477 * @param string $page Page name.
2478 *
2479 * @return bool
2480 */
2481 public static function product_filters_has_ajax( $page ) {
2482 if ( empty( $page ) ) {
2483 return false;
2484 }
2485
2486 if ( 'page' === get_post_type() ) {
2487 return false;
2488 }
2489
2490 $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page );
2491 if ( ! $id ) {
2492 return false;
2493 }
2494 $cache_key = 'product_filters_has_ajax_' . $id;
2495 if ( isset( self::$cache[ $cache_key ] ) ) {
2496 return self::$cache[ $cache_key ];
2497 }
2498 $elmap = ElementorDataMap::instance();
2499 $ajax = [];
2500
2501 foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) {
2502 $ajax[] = isset( $data['settings']['ajax_mode'] ) ? false : true;
2503 }
2504
2505 self::$cache[ $cache_key ] = ! empty( $ajax[0] );
2506 return ! empty( $ajax[0] );
2507 }
2508
2509 /**
2510 * Check if product has applied filter.
2511 *
2512 * @param string $page Page name.
2513 *
2514 * @return bool
2515 */
2516 public static function product_has_applied_filters( $page ) {
2517 if ( empty( $page ) ) {
2518 return false;
2519 }
2520
2521 $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page );
2522 $elmap = ElementorDataMap::instance();
2523 $ajax = [];
2524 if ( ! $id ) {
2525 return false;
2526 }
2527 foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) {
2528 $ajax[] = ! isset( $data['settings']['active_filter'] );
2529
2530 }
2531
2532 return ! empty( $ajax[0] );
2533 }
2534
2535 /**
2536 * Get WooCommerce product categories.
2537 *
2538 * @param string|null $search_query The search string for category names.
2539 *
2540 * @return array An array of product categories with 'value' and 'label' keys.
2541 */
2542 public static function products_category_query( $search_query = null ) {
2543 if ( ! is_admin() ) {
2544 return [];
2545 }
2546
2547 $cache_key = 'rtsb_product_categories_' . md5( serialize( $search_query ) );
2548
2549 if ( isset( self::$cache[ $cache_key ] ) ) {
2550 return self::$cache[ $cache_key ];
2551 }
2552 $results = wp_cache_get( $cache_key, 'shopbuilder' );
2553 if ( ! $results ) {
2554 global $wpdb;
2555 $sql = "SELECT t.term_id, t.name
2556 FROM {$wpdb->terms} t
2557 JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
2558 WHERE tt.taxonomy = 'product_cat'";
2559
2560 if ( $search_query ) {
2561 $sql .= ' AND t.name LIKE %s';
2562 $prepared_sql = $wpdb->prepare( $sql, '%' . $wpdb->esc_like( $search_query ) . '%' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2563 } else {
2564 $prepared_sql = $sql; // No need for placeholders.
2565 }
2566
2567 $results = $wpdb->get_results( $prepared_sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared
2568 // Cache the results in the object cache for future use.
2569 wp_cache_set( $cache_key, $results, 'shopbuilder' ); // Adjust the expiration time as needed.
2570 Cache::set_data_cache_key( $cache_key );
2571 }
2572
2573 $cats = [];
2574 if ( ! is_array( $results ) && ! count( $results ) ) {
2575 return $cats;
2576 }
2577 foreach ( $results as $row ) {
2578 $category_id = $row->term_id;
2579 $category_title = $row->name;
2580
2581 $cats[] = [
2582 'value' => $category_id,
2583 'label' => $category_title,
2584 ];
2585 }
2586
2587 // Cache the results in a static variable for the next call.
2588 self::$cache[ $cache_key ] = $cats;
2589 return $cats;
2590 }
2591 /**
2592 * Get WooCommerce product categories.
2593 *
2594 * @param string|null $search_query The search string for category names.
2595 *
2596 * @return array An array of product categories with 'value' and 'label' keys.
2597 */
2598 public static function products_tags_query( $search_query = null ) {
2599 if ( ! is_admin() ) {
2600 return [];
2601 }
2602
2603 $cache_key = 'rtsb_product_tags_' . md5( serialize( $search_query ) );
2604
2605 if ( isset( self::$cache[ $cache_key ] ) ) {
2606 return self::$cache[ $cache_key ];
2607 }
2608 $results = wp_cache_get( $cache_key, 'shopbuilder' );
2609 if ( ! $results ) {
2610 global $wpdb;
2611 $sql = "SELECT t.term_id, t.name
2612 FROM {$wpdb->terms} t
2613 JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
2614 WHERE tt.taxonomy = 'product_tag'";
2615
2616 if ( $search_query ) {
2617 $sql .= ' AND t.name LIKE %s';
2618 $prepared_sql = $wpdb->prepare( $sql, '%' . $wpdb->esc_like( $search_query ) . '%' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2619 } else {
2620 $prepared_sql = $sql; // No need for placeholders.
2621 }
2622
2623 $results = $wpdb->get_results( $prepared_sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared
2624 // Cache the results in the object cache for future use.
2625 wp_cache_set( $cache_key, $results, 'shopbuilder' ); // Adjust the expiration time as needed.
2626 Cache::set_data_cache_key( $cache_key );
2627 }
2628
2629 $cats = [];
2630 if ( ! is_array( $results ) && ! count( $results ) ) {
2631 return $cats;
2632 }
2633 foreach ( $results as $row ) {
2634 $category_id = $row->term_id;
2635 $category_title = $row->name;
2636
2637 $cats[] = [
2638 'value' => $category_id,
2639 'label' => $category_title,
2640 ];
2641 }
2642
2643 // Cache the results in a static variable for the next call.
2644 self::$cache[ $cache_key ] = $cats;
2645 return $cats;
2646 }
2647
2648 /**
2649 * @param string $search_query Search query.
2650 *
2651 * @return array
2652 */
2653 public static function get_registered_post_types( $search_query = null ) {
2654 // Get all registered post types.
2655 $registered_post_types = get_post_types(
2656 [
2657 'public' => true,
2658 '_builtin' => false,
2659 ],
2660 'objects'
2661 );
2662
2663 unset( $registered_post_types['elementor_library'] );
2664 unset( $registered_post_types['e-landing-page'] );
2665 unset( $registered_post_types['rtsb_builder'] );
2666
2667 $post_types = [];
2668
2669 // Check if a search query is provided.
2670 if ( ! empty( $search_query ) ) {
2671 // Filter post types based on the search query.
2672 $registered_post_types = array_filter(
2673 $registered_post_types,
2674 function ( $post_type ) use ( $search_query ) {
2675 return stripos( $post_type->labels->singular_name, $search_query ) !== false;
2676 }
2677 );
2678 // Check if 'post' match the search query and include them if they do.
2679 if ( stripos( 'post', $search_query ) !== false ) {
2680 $post_types[] = [
2681 'value' => 'post',
2682 'label' => 'Post',
2683 ];
2684 }
2685 } else {
2686 $post_types[] = [
2687 'value' => 'post',
2688 'label' => 'Post',
2689 ];
2690 }
2691
2692 // Convert the filtered post types to an array.
2693 foreach ( $registered_post_types as $post_type ) {
2694 $post_types[] = [
2695 'value' => $post_type->name,
2696 'label' => $post_type->labels->singular_name,
2697 ];
2698 }
2699
2700 return $post_types;
2701 }
2702
2703 /**
2704 * Get Post Types.
2705 *
2706 * @param string $search_query Search query.
2707 *
2708 * @return array
2709 */
2710 public static function get_post_types( $search_query = null, $args = [] ) {
2711
2712 $args = wp_parse_args(
2713 $args,
2714 [
2715 'post_type' => 'any',
2716 'posts_per_page' => 20,
2717 'orderby' => 'ID',
2718 'order' => 'DESC',
2719 // 'suppress_filters' => false, // WPML Support, Remove Others Languages.
2720 ]
2721 );
2722
2723 if ( 'archive' !== $args['post_type'] ) {
2724 if ( $search_query ) {
2725 $args['s'] = $search_query;
2726 }
2727 $posts = [];
2728 $query_results = get_posts( $args );
2729 foreach ( $query_results as $post ) {
2730 $posts[] = [
2731 'value' => $post->ID,
2732 'label' => $post->post_title . ' ( ID ' . $post->ID . ')',
2733 ];
2734 }
2735
2736 if ( $search_query ) {
2737 if ( strpos( '-error 404', $search_query ) ) {
2738 $posts[] = [
2739 'value' => 'error',
2740 'label' => __( '404 Error', 'shopbuilder' ),
2741 ];
2742 }
2743 } else {
2744 if ( 'page' === $args['post_type'] ) {
2745 $posts[] = [
2746 'value' => 'error',
2747 'label' => __( '404 Error', 'shopbuilder' ),
2748 ];
2749 }
2750 }
2751 } else {
2752 $posts = self::get_registered_post_types( $search_query );
2753 }
2754
2755 return $posts;
2756 }
2757
2758 /**
2759 * Get all Elementor breakpoints.
2760 *
2761 * @return array
2762 */
2763 public static function get_elementor_breakpoints() {
2764 return ( new \Elementor\Core\Breakpoints\Manager() )->get_breakpoints_config();
2765 }
2766
2767 /**
2768 * Render view.
2769 *
2770 * @param string $viewName View name.
2771 * @param array $args View args.
2772 * @param boolean $return View return.
2773 * @return string|void
2774 */
2775 public static function renderView( $viewName, $args = [], $return = false ) {
2776 $viewName = str_replace( '.', '/', $viewName );
2777
2778 if ( ! empty( $args ) && is_array( $args ) ) {
2779 extract( $args );
2780 }
2781
2782 $view_file = rtsb()->plugin_path() . '/resources/' . $viewName . '.php';
2783
2784 if ( ! file_exists( $view_file ) ) {
2785 _doing_it_wrong( __FUNCTION__, sprintf( '<code>%s</code> does not exist.', esc_html( $view_file ) ), '1.7.0' );
2786
2787 return;
2788 }
2789
2790 if ( $return ) {
2791 ob_start();
2792 include $view_file;
2793
2794 return ob_get_clean();
2795 } else {
2796 include $view_file;
2797 }
2798 }
2799
2800 /**
2801 * Best selling product query.
2802 *
2803 * @param int $minimum_sale Minimum sale/
2804 * @param int $limit Total limit.
2805 *
2806 * @return array|mixed
2807 */
2808 public static function best_selling_products_ids( $minimum_sale = 1, $limit = 10 ) {
2809 $cache_key = 'rtsb_best_selling_products_' . $minimum_sale . '_' . $limit;
2810 // Check if the data is in the cache.
2811 if ( isset( self::$cache[ $cache_key ] ) ) {
2812 return self::$cache[ $cache_key ];
2813 }
2814 $cached_data = get_transient( $cache_key );
2815 if ( $cached_data ) {
2816 self::$cache[ $cache_key ] = $cached_data;
2817 return $cached_data;
2818 }
2819 global $wpdb;
2820 $sql = $wpdb->prepare(
2821 "
2822 SELECT ID
2823 FROM {$wpdb->posts} AS p
2824 LEFT JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id
2825 WHERE p.post_type = 'product'
2826 AND p.post_status = 'publish'
2827 AND pm.meta_key = 'total_sales'
2828 AND pm.meta_value >= %d
2829 ORDER BY pm.meta_value + 0 DESC
2830 LIMIT %d
2831 ",
2832 $minimum_sale,
2833 $limit
2834 );
2835 $best_selling = $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
2836 // Cache the result for future use.
2837 set_transient( $cache_key, $best_selling, DAY_IN_SECONDS );
2838 self::$cache[ $cache_key ] = $best_selling;
2839 return $best_selling;
2840 }
2841
2842 /**
2843 * @param null|Object $product Product Object.
2844 * @param int $days_threshold Date String.
2845 *
2846 * @return bool
2847 */
2848 public static function is_new_product( $product = null, $days_threshold = 30 ) {
2849 if ( is_null( $product ) ) {
2850 global $product;
2851 }
2852 if ( ! $product instanceof WC_Product ) {
2853 return false;
2854 }
2855
2856 $product_id = $product->get_id();
2857 $days_threshold = ! empty( $days_threshold ) ? $days_threshold : 30;
2858 $cache_key = 'is_new_product_' . $product_id . '_' . $days_threshold;
2859
2860 if ( isset( self::$cache[ $cache_key ] ) ) {
2861 return self::$cache[ $cache_key ];
2862 }
2863 $date_created = $product->get_date_created();
2864 if ( ! $date_created ) {
2865 return false;
2866 }
2867 $publish_timestamp = strtotime( $date_created->date_i18n( 'Y-m-d H:i:s' ) );
2868
2869 // Calculate the difference in days.
2870 $days_difference = abs( time() - $publish_timestamp ) / ( 60 * 60 * 24 );
2871
2872 // Check if the product is considered new.
2873 $is_new = $days_difference <= $days_threshold;
2874
2875 // Cache the result for a day.
2876 self::$cache[ $cache_key ] = $is_new;
2877
2878 return $is_new;
2879 }
2880
2881 /**
2882 * Checks if a feature is disabled for guest users based on the provided option.
2883 *
2884 * @param string $option The option to retrieve from the item.
2885 * @param mixed $default The default value if the option is not found.
2886 *
2887 * @return bool
2888 */
2889 public static function is_guest_feature_disabled( $option, $default ) {
2890 $disabled = self::get_option( 'general', 'guest_user', $option, $default );
2891
2892 return ! is_user_logged_in() && $disabled;
2893 }
2894
2895 /**
2896 * Checks if a feature is disabled for guest users based on the provided option.
2897 *
2898 * @param string $option The option to retrieve from the item.
2899 * @param mixed $default The default value if the option is not found.
2900 *
2901 * @return bool
2902 */
2903 public static function woocommerce_output_all_notices() {
2904 if ( function_exists( 'wc_print_notices' ) ) :
2905 echo '<div class="rtsb-notice">';
2906 woocommerce_output_all_notices();
2907 echo '</div>';
2908 endif;
2909 }
2910
2911 /**
2912 * @param object $product Product.
2913 * @return bool
2914 */
2915 public static function is_visible_qty_input( $product = null ) {
2916 $is_visible_qty = true;
2917 if ( $product instanceof \WC_Product ) {
2918 if ( $product->is_sold_individually() ) {
2919 $is_visible_qty = false;
2920 } elseif ( $product->managing_stock() ) {
2921 if ( in_array( $product->get_backorders(), [ 'notify' , 'yes' ], true ) ) {
2922 $is_visible_qty = true;
2923 } elseif ( $product->get_stock_quantity() < 2 ) {
2924 $is_visible_qty = false;
2925 }
2926 }
2927 }
2928 return $is_visible_qty;
2929 }
2930
2931 /**
2932 * @param int $object_id Object id.
2933 * @param string $element_type element type.
2934 * @param string|null $current_lang null for current language, default for default languages.
2935 * @return false|mixed|null
2936 */
2937 public static function wpml_object_id( $object_id, $element_type, $current_lang = 'default' ) {
2938 if ( ! defined( 'ICL_SITEPRESS_VERSION' ) ) {
2939 return $object_id;
2940 }
2941 if ( ! $object_id || ! $element_type ) {
2942 return $object_id;
2943 }
2944 if ( 'default' === $current_lang ) {
2945 $lang = apply_filters( 'wpml_default_language', null );
2946 } else {
2947 $lang = null;
2948 }
2949 return apply_filters( 'wpml_object_id', $object_id, $element_type, false, $lang );
2950 }
2951
2952 /**
2953 * @return string
2954 */
2955 public static function wpml_current_language() {
2956 $current = apply_filters( 'wpml_current_language', null );
2957 $default = apply_filters( 'wpml_default_language', null );
2958 return $default !== $current ? $current : null;
2959 }
2960
2961 /**
2962 * Custom icons.
2963 *
2964 * @return string[]
2965 */
2966 public static function get_custom_icon_names() {
2967 return [
2968 'heart-empty',
2969 'heart',
2970 'eye',
2971 'exchange',
2972 'plus',
2973 'minus',
2974 'avatar',
2975 'pay',
2976 'share',
2977 'clock',
2978 'check-alt',
2979 'check',
2980 'delete',
2981 'marker',
2982 'list',
2983 'list-2',
2984 'power',
2985 'cart',
2986 'cart-2',
2987 'cart-3',
2988 'downloads',
2989 'zoom',
2990 'user-edit',
2991 'grid',
2992 'filter',
2993 'billing',
2994 'login',
2995 'payment',
2996 'search',
2997 'edit',
2998 'coupon',
2999 'arrows-cw',
3000 'trash-empty',
3001 ];
3002 }
3003
3004 /**
3005 * Retrieve an array of custom icons with their HTML representation.
3006 *
3007 * @return array
3008 */
3009 public static function get_icons() {
3010 $icon = self::get_custom_icon_names();
3011 $icons_array = [];
3012 foreach ( $icon as $value ) {
3013 $icons_array[ $value ] = '<i class="rtsb-icon rtsb-icon-' . $value . '"></i> <span class="icon-name">' . ucfirst( str_replace( '-', ' ', $value ) ) . '</span>';
3014 }
3015 return $icons_array;
3016 }
3017
3018 /**
3019 * Generates HTML markup for displaying an endpoint icon.
3020 *
3021 * @param array $data The endpoint data containing icon information.
3022 * @param string $endpoint The endpoint identifier.
3023 * @param boolean $wrapper Whether to wrap the icon in a span element.
3024 *
3025 * @return string
3026 */
3027 public static function get_icon_html( $data, $wrapper = true ) {
3028 if ( empty( $data ) || 'none' === $data['icon_source'] ) {
3029 return '';
3030 }
3031 $endpoint = '';
3032 $html = $wrapper ? '<span class="icon ' . esc_attr( $endpoint ) . '_icon">' : '';
3033
3034 if ( 'select_icon' === $data['icon_source'] ) {
3035 $html .= '<i class="rtsb-icon rtsb-icon-' . esc_attr( $data['custom_icon'] ) . '"></i>';
3036 } else {
3037 $icon_html = '';
3038 $icon_url = $data['image_icon']['source'] ?? '';
3039 $icon_id = $data['image_icon']['id'] ?? 0;
3040 $extension = ! empty( $icon_url ) ? strtolower( substr( strrchr( $data['image_icon']['source'], '.' ), 1 ) ) : '';
3041
3042 if ( 'svg' === $extension ) {
3043 $content = file_get_contents( $icon_url ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
3044 $is_svg = strpos( $content, '<svg' );
3045
3046 if ( false !== $is_svg ) {
3047 $icon_html = substr( $content, $is_svg );
3048 }
3049 } else {
3050 $attr = [
3051 'class' => 'rtsb-icon-img',
3052 'alt' => esc_html( ucfirst( $endpoint ) ) . esc_html__( ' Icon', 'shopbuilder' ),
3053 ];
3054
3055 $icon_html = wp_get_attachment_image( absint( $icon_id ), 'full', true, $attr );
3056 }
3057
3058 $html .= $icon_html;
3059 }
3060
3061 $html .= $wrapper ? '</span>' : '';
3062
3063 return $html;
3064 }
3065 /**
3066 * Flushes rewrite rules.
3067 *
3068 * @return void
3069 */
3070 public static function maybe_flush_rewrite_rules() {
3071 add_action( 'wp_loaded', [ __CLASS__, 'flush_rewrite_rules' ] );
3072 add_action( 'shutdown', [ __CLASS__, 'flush_rewrite_rules_once_more' ] );
3073 }
3074
3075 /**
3076 * Flushes rewrite rules if needed.
3077 *
3078 * @return void
3079 */
3080 public static function flush_rewrite_rules() {
3081 if ( get_option( 'rtsb_permalinks_need_flush' ) === 'yes' ) {
3082 flush_rewrite_rules();
3083 }
3084
3085 if ( get_option( 'rtsb_permalinks_flushed' ) === 'yes' ) {
3086 flush_rewrite_rules();
3087 delete_option( 'rtsb_permalinks_flushed' );
3088 }
3089 }
3090
3091 /**
3092 * Flushes rewrite rules if needed for second time.
3093 *
3094 * @return void
3095 */
3096 public static function flush_rewrite_rules_once_more() {
3097 if ( get_option( 'rtsb_permalinks_need_flush' ) === 'yes' ) {
3098 flush_rewrite_rules();
3099 update_option( 'rtsb_permalinks_flushed', 'yes' );
3100 delete_option( 'rtsb_permalinks_need_flush' );
3101 }
3102 }
3103
3104 /**
3105 * Social Share Platforms.
3106 *
3107 * @return mixed|null
3108 */
3109 public static function set_repeater_options( $section_id, $block_id, $option_key, $compare_key, $compare_value, $values ) {
3110 // $options = self::get_options( $section_id, $block_id );
3111 $modules = DataModel::source()->get_option( $section_id, [], false );
3112 if ( empty( $modules[ $block_id ] ) ) {
3113 return;
3114 }
3115 $options = $modules[ $block_id ];
3116 if ( empty( $options[ $option_key ] ) ) {
3117 return;
3118 }
3119 $repeater_options = json_decode( $options[ $option_key ], true );
3120 // Check if options are not empty and are in array format.
3121 if ( ! is_array( $repeater_options ) ) {
3122 return;
3123 }
3124 // Use array_column to get an array of values from $compare_key.
3125 $column_values = array_column( $repeater_options, $compare_key );
3126 // Use array_search to find the index of the $compare_value.
3127 $index = array_search( $compare_value, $column_values, true );
3128 if ( false === $index ) {
3129 return;
3130 }
3131 $repeater_options[ $index ] = wp_parse_args( $values, $repeater_options[ $index ] );
3132 $options[ $option_key ] = wp_json_encode( $repeater_options );
3133 $modules[ $block_id ] = $options;
3134 DataModel::source()->set_option( $section_id, $modules );
3135 }
3136
3137
3138 /**
3139 * @param array $ids products id.
3140 * @return array
3141 */
3142 public static function get_available_products_by_ids( $ids = [] ) {
3143 $ids = array_filter(
3144 $ids,
3145 function ( $id ) {
3146 return 'product' === get_post_type( $id ) && 'publish' === get_post_status( $id );
3147 }
3148 );
3149 return $ids;
3150 }
3151
3152 /**
3153 * Generate and cache dynamic CSS styles.
3154 *
3155 * @param array $options CSS options to apply (e.g. padding, margin).
3156 * @param string $cache_key Cache key for the CSS.
3157 * @param array $css_properties An array of CSS properties with selectors and properties.
3158 * @param string $style_handle The handle for the inline styles.
3159 *
3160 * @return void
3161 */
3162 public static function dynamic_styles( $options, $cache_key, $css_properties, $style_handle = 'rtsb-frontend' ) {
3163 $cached_css = wp_cache_get( $cache_key, 'shopbuilder' );
3164
3165 if ( false !== $cached_css ) {
3166 wp_add_inline_style( $style_handle, $cached_css );
3167 return;
3168 }
3169
3170 $css_rules = [];
3171 $grouped_css_rules = [];
3172
3173 foreach ( $css_properties as $option => $details ) {
3174 if ( ! empty( $options[ $option ] ) ) {
3175 $selector = $details['selector'] ?? '';
3176 $property = $details['property'] ?? '';
3177 $unit = $details['unit'] ?? '';
3178 $value = $options[ $option ];
3179
3180 if ( empty( $grouped_css_rules[ $selector ] ) ) {
3181 $grouped_css_rules[ $selector ] = [];
3182 }
3183
3184 if ( is_array( $property ) ) {
3185 foreach ( $property as $prop ) {
3186 $grouped_css_rules[ $selector ][] = $prop . ': ' . $value . $unit . ' !important';
3187 }
3188 } else {
3189 $grouped_css_rules[ $selector ][] = $property . ': ' . $value . $unit . ' !important';
3190 }
3191 }
3192 }
3193
3194 foreach ( $grouped_css_rules as $selector => $properties ) {
3195 $css_rules[] = $selector . ' {' . implode( '; ', $properties ) . '}';
3196 }
3197
3198 $dynamic_css = implode( ' ', $css_rules );
3199
3200 wp_cache_set( $cache_key, $dynamic_css, 'shopbuilder', 12 * HOUR_IN_SECONDS );
3201 Cache::set_data_cache_key( $cache_key );
3202
3203 if ( ! empty( $dynamic_css ) ) {
3204 wp_add_inline_style( $style_handle, $dynamic_css );
3205 }
3206 }
3207
3208 /**
3209 * Pro version notice.
3210 *
3211 * @param string $ver Pro Version.
3212 *
3213 * @return array[]
3214 */
3215 public static function pro_version_notice( $ver, $tab = 'billing_fields', $name = 'ShopBuilder', $enable_free_Link = true ) {
3216 return [
3217 'version_check' => [
3218 'id' => 'version_check',
3219 'type' => 'title',
3220 'label' => sprintf(
3221 /* translators: 1: required version, 2: link to the Plugins page */
3222 esc_html__(
3223 'To access all features and settings of this module, please ensure that "%1$s" is updated to version %2$s. %3$s',
3224 'shopbuilder'
3225 ),
3226 $name,
3227 sprintf(
3228 '<br /><u><b>%s</b></u>',
3229 esc_html( $ver ?? '1.5.0' ) . ' or higher'
3230 ),
3231 $enable_free_Link
3232 ? sprintf(
3233 '%s <a class="pro-update-required" href="%s" target="_blank" title="%s">%s</a>',
3234 esc_attr__( 'Update to the latest version', 'shopbuilder' ),
3235 esc_url( admin_url( 'plugins.php' ) ),
3236 esc_attr__( 'Go to the Plugin Page', 'shopbuilder' ),
3237 esc_html__( 'from the Plugins page', 'shopbuilder' )
3238 )
3239 : ''
3240 ),
3241 'tab' => $tab,
3242 'customClass' => 'checkout-notice',
3243 ],
3244 ];
3245 }
3246
3247 /**
3248 * Get product gallery ids.
3249 *
3250 * @param object $product Product object.
3251 *
3252 * @return mixed
3253 */
3254 public static function get_cached_gallery_ids( $product ) {
3255 $product_id = $product->get_id();
3256 $cache_key = 'rtsb_product_gallery_ids_' . $product_id;
3257
3258 if ( isset( self::$cache[ $cache_key ] ) ) {
3259 return self::$cache[ $cache_key ];
3260 }
3261
3262 $cached_result = wp_cache_get( $cache_key, 'shopbuilder' );
3263
3264 if ( false !== $cached_result ) {
3265 self::$cache[ $cache_key ] = $cached_result;
3266
3267 return $cached_result;
3268 }
3269
3270 $gallery_ids = $product->get_gallery_image_ids();
3271 self::$cache[ $cache_key ] = $gallery_ids;
3272
3273 wp_cache_set( $cache_key, $gallery_ids, 'shopbuilder', 12 * HOUR_IN_SECONDS );
3274 Cache::set_data_cache_key( $cache_key );
3275
3276 return $gallery_ids;
3277 }
3278 }
3279