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

2,326 lines 69.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Fns Helpers class
4 *
5 * @package RadiusTheme\SB
6 */
7
8 namespace RadiusTheme\SB\Helpers;
9
10 // Do not allow directly accessing this file.
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit( 'This script cannot be accessed directly.' );
13 }
14
15 use Elementor\Icons_Manager;
16 use RadiusTheme\SB\Models\ReSizer;
17 use RadiusTheme\SB\Models\DataModel;
18 use RadiusTheme\SB\Models\ModuleList;
19 use RadiusTheme\SB\Models\Settings;
20 use WC_Product;
21
22 /**
23 * Fns class
24 */
25 class Fns {
26
27 /**
28 * Verify nonce.
29 *
30 * @return bool
31 */
32 public static function verify_nonce() {
33 $nonce = isset( $_REQUEST[ rtsb()->nonceId ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ rtsb()->nonceId ] ) ) : null;
34 $nonceText = rtsb()->nonceText;
35 if ( wp_verify_nonce( $nonce, $nonceText ) ) {
36 return true;
37 }
38
39 return false;
40 }
41
42 /**
43 * @param $plugin_slug
44 *
45 * @return bool
46 */
47 public static function check_plugin_installed( $plugin_slug ): bool {
48 $installed_plugins = get_plugins();
49
50 return array_key_exists( $plugin_slug, $installed_plugins ) || in_array( $plugin_slug, $installed_plugins, true );
51 }
52
53 /**
54 * @param $plugin_slug
55 *
56 * @return bool
57 */
58 public static function check_plugin_active( $plugin_slug ): bool {
59 if ( is_plugin_active( $plugin_slug ) ) {
60 return true;
61 }
62
63 return false;
64 }
65
66 /**
67 * @param $data
68 *
69 * @return mixed|string
70 */
71 public static function stripslashes_value( $data ) {
72 if ( is_string( $data ) && strpos( $data, '\\' ) !== false ) {
73 return stripslashes( $data );
74 } elseif ( is_array( $data ) ) {
75 foreach ( $data as $key => $value ) {
76 $data[ $key ] = self::stripslashes_value( $value );
77 }
78 }
79
80 return $data;
81 }
82
83 /**
84 * @param $string
85 *
86 * @return array
87 */
88 public static function multiselect_settings_field_value( $string ) {
89
90 $values = [];
91 if ( empty( $string ) ) {
92 return $values;
93 }
94
95 $stripslashes_data = self::stripslashes_value( $string );
96 if ( is_array( $stripslashes_data ) && count( $stripslashes_data ) ) {
97 foreach ( $stripslashes_data as $item ) {
98 $item = is_array( $item ) ? $item : json_decode( $item, true );
99 $values[] = $item['value'];
100 }
101 }
102
103 return $values;
104 }
105
106 /**
107 * @return bool
108 */
109 public static function check_is_block_theme(): bool {
110 global $wp_version;
111
112 return version_compare( $wp_version, '5.9', '>=' ) && function_exists( 'wp_is_block_theme' ) && wp_is_block_theme();
113 }
114
115 /**
116 * @param string $template_name Template name.
117 * @param string $template_path Template path. (default: '').
118 * @param string $plugin_path Plugin path. (default: ''). fallback file from plugin
119 *
120 * @return mixed|void
121 */
122 public static function locate_template( $template_name, $template_path = '', $plugin_path = '' ) {
123 $template_name = $template_name . '.php';
124 if ( ! $template_path ) {
125 $template_path = rtsb()->get_template_path();
126 }
127 if ( ! $plugin_path ) {
128 $plugin_path = RTSB_ABSPATH . 'templates/';
129 }
130
131 $template_rtsb_path = trailingslashit( $template_path ) . $template_name;
132 $template_path = '/' . $template_name;
133 $plugin_path = $plugin_path . $template_name;
134 $pro_plugin_path = rtsb()->has_pro() ? RTSBPRO_PATH . 'templates/' . $template_name : '';
135
136 $located = locate_template(
137 apply_filters(
138 'rtsb/core/locate_template_files',
139 [
140 $template_rtsb_path, // Search in <theme>/shopbuilder/.
141 $template_path, // Search in <theme>/.
142 ]
143 )
144 );
145
146 if ( ! $located ) {
147 if ( file_exists( $plugin_path ) ) {
148 return apply_filters( 'rtsb/core/locate_template', $plugin_path, $template_name );
149 } elseif ( $pro_plugin_path && rtsb()->has_pro() && file_exists( $pro_plugin_path ) ) {
150 return apply_filters( 'rtsb/core/locate_template', $pro_plugin_path, $template_name );
151 }
152 }
153
154 /**
155 * APPLY_FILTERS: rtsb/core/locate_template
156 *
157 * Filter the location of the templates.
158 *
159 * @param string $located Template found
160 * @param string $path Template path
161 *
162 * @return string
163 */
164 return apply_filters( 'rtsb/core/locate_template', $located, $template_name );
165 }
166
167 /**
168 * Template Content
169 *
170 * @param string $template_name Template name.
171 * @param array $args Arguments. (default: array).
172 * @param bool $return Whether to return or print the template.
173 * @param string $template_path Template path. (default: '').
174 * @param string $plugin_path Fallback path from where file will load if fail to load from template. (default: '').
175 *
176 * @return false|string|void
177 */
178 public static function load_template( $template_name, array $args = null, $return = false, $template_path = '', $plugin_path = '' ) {
179 $located = self::locate_template( $template_name, $template_path, $plugin_path );
180
181 if ( ! file_exists( $located ) ) {
182 // translators: %s template.
183 self::doing_it_wrong( __FUNCTION__, sprintf( __( '%s does not exist.', 'shopbuilder' ), '<code>' . $located . '</code>' ), '1.0' );
184
185 return;
186 }
187
188 if ( ! empty( $args ) && is_array( $args ) ) {
189 $atts = $args;
190 extract( $args ); // @codingStandardsIgnoreLine
191 }
192
193 // Allow 3rd party plugin filter template file from their plugin.
194 $located = apply_filters( 'rtsb/core/get_template', $located, $template_name, $args );
195
196 if ( $return ) {
197 ob_start();
198 }
199
200 do_action( 'rtsb/core/before_template_part', $template_name, $located, $args );
201 include $located;
202 do_action( 'rtsb/core/after_template_part', $template_name, $located, $args );
203
204 if ( $return ) {
205 return ob_get_clean();
206 }
207 }
208
209 /**
210 * Verify nonce.
211 *
212 * @return string
213 */
214 public static function is_woocommerce() {
215 return is_woocommerce() || is_cart() || is_checkout() || is_account_page();
216 }
217
218 /**
219 * Page builder
220 *
221 * @param int $post_id post id.
222 *
223 * @return string
224 */
225 public static function page_edit_with( $post_id ) {
226 if ( ! $post_id ) {
227 return '';
228 }
229
230 $edit_with = get_post_meta( $post_id, '_elementor_edit_mode', true );
231
232 if ( 'builder' === $edit_with ) {
233 $edit_by = 'elementor';
234 } else {
235 $edit_by = 'gutenberg';
236 }
237
238 return $edit_by;
239 }
240
241 /**
242 * Returns default expiration for wishlist cookie
243 *
244 * @return int Number of seconds the cookie should last.
245 */
246 public static function get_cookie_expiration() {
247 return intval( apply_filters( 'rtsb/cookie_expiration', 60 * 60 * 24 * 30 ) );
248 }
249
250 /**
251 * Create a cookie.
252 *
253 * @param string $name Cookie name.
254 * @param mixed $value Cookie value.
255 * @param int $time Cookie expiration time.
256 * @param bool $secure Whether cookie should be available to secured connection only.
257 * @param bool $httponly Whether cookie should be available to HTTP request only (no js handling).
258 *
259 * @return bool
260 * @since 1.0.0
261 */
262 public static function setcookie( $name, $value = [], $time = null, $secure = false, $httponly = false ) {
263
264 if ( ! apply_filters( 'rtsb/set_cookie', true ) || empty( $name ) ) {
265 return false;
266 }
267
268 $time = ! empty( $time ) ? $time : time() + self::get_cookie_expiration();
269
270 $value = wp_json_encode( stripslashes_deep( $value ) );
271 $expiration = apply_filters( 'rtsb/cookie_expiration_time', $time ); // Default 30 days.
272
273 $_COOKIE[ $name ] = $value;
274 wc_setcookie( $name, $value, $expiration, $secure, $httponly );
275
276 return true;
277 }
278
279 /**
280 * Retrieve the value of a cookie.
281 *
282 * @param string $name Cookie name.
283 *
284 * @return mixed
285 * @since 1.0.0
286 */
287 public static function getcookie( $name ) {
288 if ( isset( $_COOKIE[ $name ] ) ) {
289 return json_decode( sanitize_text_field( wp_unslash( $_COOKIE[ $name ] ) ), true );
290 }
291
292 return [];
293 }
294
295 /**
296 * Woocommerce Last product id return
297 */
298 public static function get_prepared_product_id() {
299 if ( is_singular( 'product' ) ) {
300 return get_the_ID();
301 }
302 // Return the Builder Template id.
303
304 if ( get_post_type( get_the_ID() ) == BuilderFns::$post_type_tb ) {
305 $product_id = get_post_meta( get_the_ID(), BuilderFns::$product_template_meta, true );
306 if ( $product_id ) {
307 return $product_id;
308 }
309 }
310
311 global $wpdb;
312 $cache_key = 'rtsb_prepared_product_id';
313 $_post_id = wp_cache_get( $cache_key );
314
315 if ( false === $_post_id || 'publish' !== get_post_status( $_post_id ) ) {
316 $_post_id = $wpdb->get_var(
317 $wpdb->prepare( "SELECT MAX(ID) FROM {$wpdb->prefix}posts WHERE post_type = %s AND post_status = %s", 'product', 'publish' )
318 );
319 wp_cache_set( $cache_key, $_post_id, '', 12 * HOUR_IN_SECONDS );
320 }
321
322 return $_post_id;
323 }
324
325 /**
326 * Get the product function.
327 *
328 * @return object
329 */
330 public static function get_product() {
331 global $post, $product;
332 if ( is_singular( 'product' ) && $product instanceof WC_Product ) {
333 return $product;
334 }
335
336 return wc_get_product( self::get_prepared_product_id() );
337 }
338
339 /**
340 * Error function
341 *
342 * @param [type] $function function name.
343 * @param [type] $message message.
344 * @param [type] $version version.
345 *
346 * @return void
347 */
348 public static function doing_it_wrong( $function, $message, $version ) {
349 $message .= ' Backtrace: ' . wp_debug_backtrace_summary();
350 _doing_it_wrong( $function, $message, $version );
351 }
352
353 /**
354 * @return array
355 */
356 public static function get_pages() {
357 $pages = [];
358 $rawPages = get_pages();
359 if ( ! empty( $rawPages ) ) {
360 foreach ( $rawPages as $page ) {
361 $pages[ $page->ID ] = $page->post_title;
362 }
363 }
364
365 return $pages;
366 }
367
368 public static function get_section_items( $section_id ) {
369 if ( ! $section_id ) {
370 return [];
371 }
372
373 return DataModel::source()->get_option( $section_id, [] );
374 }
375
376 public static function get_options( $section_id, $item_id ) {
377 if ( ! $section_id || ! $item_id ) {
378 return [];
379 }
380 $sections = self::get_section_items( $section_id );
381
382 return isset( $sections[ $item_id ] ) ? $sections[ $item_id ] : [];
383 }
384
385 /**
386 * Get options value with default value if options doesn't exist.
387 *
388 * @param $group
389 * @param $option_key
390 * @param $default_value
391 *
392 * @return mixed|string
393 */
394 public static function get_options_by_default_val( $group, $option_key, $default_value = '' ) {
395
396 if ( ! $option_key || ! isset( $group[ $option_key ] ) ) {
397 return $default_value;
398 }
399
400 return $group[ $option_key ];
401 }
402
403 /**
404 * @param string $section_id
405 * @param string $item_id
406 * @param string $option_id
407 * @param null $default EXCEPT multi_checkbox you can provide default value if given option does not set any value
408 * @param null $type checkbox, multi_checkbox, number
409 *
410 * @return bool|int|mixed|null
411 */
412 public static function get_option( $section_id, $item_id, $option_id, $default = null, $type = null ) {
413 $options = self::get_options( $section_id, $item_id );
414
415 if ( $type === 'checkbox' ) {
416 if ( isset( $options[ $option_id ] ) ) {
417 return $options[ $option_id ] === 'on';
418 }
419
420 return $default;
421 } elseif ( $type === 'multi_checkbox' ) {
422 return isset( $options[ $option_id ] ) && is_array( $options[ $option_id ] ) && in_array( $default, $options[ $option_id ] );
423 } elseif ( $type === 'number' ) {
424 return isset( $options[ $option_id ] ) ? absint( $options[ $option_id ] ) : absint( $default );
425 }
426
427 return isset( $options[ $option_id ] ) && ! empty( $options[ $option_id ] ) ? $options[ $option_id ] : $default;
428 }
429
430
431 /**
432 * Create a page and store the ID in an option.
433 *
434 * @param mixed $slug Slug for the new page.
435 * @param array $options ['section_id', 'item_id', 'option_id']Option name to store the page's ID.
436 * @param string $page_title (default: '') Title for the new page.
437 * @param string $page_content (default: '') Content for the new page.
438 * @param int $post_parent (default: 0) Parent for the new page.
439 * @param string $post_status (default: publish) The post status of the new page.
440 *
441 * @return int page ID.
442 */
443 public static function create_page( $slug, $options = '', $page_title = '', $page_content = '', $post_parent = 0, $post_status = 'publish' ) {
444 global $wpdb;
445
446 $option_value = 0;
447 if ( ! empty( $options ) ) {
448 if ( is_array( $options ) ) {
449 $options = wp_parse_args(
450 $options,
451 [
452 'section_id' => '',
453 'item_id' => '',
454 'option_id' => '',
455 ]
456 );
457 $option_value = self::get_option( $options['section_id'], $options['item_id'], $options['option_id'], 0, 'number' );
458 } else {
459 $option_value = absint( get_option( $options ) );
460 }
461 }
462
463 if ( $option_value > 0 ) {
464 $page_object = get_post( $option_value );
465
466 if ( $page_object && 'page' === $page_object->post_type && ! in_array(
467 $page_object->post_status,
468 [
469 'pending',
470 'trash',
471 'future',
472 'auto-draft',
473 ],
474 true
475 ) ) {
476 // Valid page is already in place.
477 return $page_object->ID;
478 }
479 }
480
481 if ( strlen( $page_content ) > 0 ) {
482 // Search for an existing page with the specified page content (typically a shortcode).
483 $shortcode = str_replace( [ '<!-- wp:shortcode -->', '<!-- /wp:shortcode -->' ], '', $page_content );
484 $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}%" ) );
485 } else {
486 // Search for an existing page with the specified page slug.
487 $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 ) );
488 }
489
490 $valid_page_found = apply_filters( 'rtsb/core/create_page_id', $valid_page_found, $slug, $page_content, $options );
491
492 if ( $valid_page_found ) {
493 if ( is_array( $options ) ) {
494 if ( ! empty( $options['section_id'] ) && $options['item_id'] && $options['option_id'] ) {
495 $section_items = DataModel::source()->get_option( $options['section_id'], [] );
496 $section_items[ $options['item_id'] ][ $options['option_id'] ] = $valid_page_found;
497 DataModel::source()->set_option( $options['section_id'], $section_items );
498 }
499 } else {
500 if ( $options ) {
501 update_option( $options, $valid_page_found );
502 }
503 }
504
505 return $valid_page_found;
506 }
507
508 // Search for a matching valid trashed page.
509 if ( strlen( $page_content ) > 0 ) {
510 // Search for an existing page with the specified page content (typically a shortcode).
511 $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}%" ) );
512 } else {
513 // Search for an existing page with the specified page slug.
514 $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 ) );
515 }
516
517 if ( $trashed_page_found ) {
518 $page_id = $trashed_page_found;
519 $page_data = [
520 'ID' => $page_id,
521 'post_status' => $post_status,
522 ];
523 wp_update_post( $page_data );
524 } else {
525 $page_data = [
526 'post_status' => $post_status,
527 'post_type' => 'page',
528 'post_author' => 1,
529 'post_name' => $slug,
530 'post_title' => $page_title,
531 'post_content' => $page_content,
532 'post_parent' => $post_parent,
533 'comment_status' => 'closed',
534 ];
535 $page_id = wp_insert_post( $page_data );
536
537 do_action( 'rtsb/core/page_created', $page_id, $page_data );
538 }
539
540 if ( is_array( $options ) ) {
541 if ( ! empty( $options['section_id'] ) && $options['item_id'] && $options['option_id'] ) {
542 $section_items = DataModel::source()->get_option( $options['section_id'], [] );
543 $section_items[ $options['item_id'] ][ $options['option_id'] ] = $page_id;
544 DataModel::source()->set_option( $options['section_id'], $section_items );
545 }
546 } else {
547 if ( $options ) {
548 update_option( $options, $page_id );
549 }
550 }
551
552 return $page_id;
553 }
554
555 public static function get_kses_array() {
556 return [
557 'a' => [
558 'class' => [],
559 'href' => [],
560 'rel' => [],
561 'title' => [],
562 ],
563 'abbr' => [
564 'title' => [],
565 ],
566 'b' => [],
567 'blockquote' => [
568 'cite' => [],
569 ],
570 'cite' => [
571 'title' => [],
572 ],
573 'code' => [],
574 'del' => [
575 'datetime' => [],
576 'title' => [],
577 ],
578 'dd' => [],
579 'div' => [
580 'class' => [],
581 'title' => [],
582 'style' => [],
583 ],
584 'dl' => [],
585 'dt' => [],
586 'em' => [],
587 'h1' => [
588 'class' => [],
589 ],
590 'h2' => [
591 'class' => [],
592 ],
593 'h3' => [
594 'class' => [],
595 ],
596 'h4' => [
597 'class' => [],
598 ],
599 'h5' => [
600 'class' => [],
601 ],
602 'h6' => [
603 'class' => [],
604 ],
605 'i' => [
606 'class' => [],
607 ],
608 'img' => [
609 'alt' => [],
610 'class' => [],
611 'height' => [],
612 'src' => [],
613 'width' => [],
614 ],
615 'li' => [
616 'class' => [],
617 ],
618 'ol' => [
619 'class' => [],
620 ],
621 'p' => [
622 'class' => [],
623 ],
624 'q' => [
625 'cite' => [],
626 'title' => [],
627 ],
628 'span' => [
629 'class' => [],
630 'title' => [],
631 'style' => [],
632 ],
633 'iframe' => [
634 'width' => [],
635 'height' => [],
636 'scrolling' => [],
637 'frameborder' => [],
638 'allow' => [],
639 'src' => [],
640 ],
641 'strike' => [],
642 'br' => [],
643 'strong' => [],
644 'data-wow-duration' => [],
645 'data-wow-delay' => [],
646 'data-wallpaper-options' => [],
647 'data-stellar-background-ratio' => [],
648 'ul' => [
649 'class' => [],
650 ],
651 ];
652 }
653
654
655 /*
656 * Escape output of wishlist icon
657 *
658 * @param string $data Data to escape.
659 * @return string Escaped data
660 */
661 public static function print_icon( $data ) {
662 /**
663 * APPLY_FILTERS: rtsb/core/allowed_icon_html
664 *
665 * Filter the allowed HTML for the icons.
666 *
667 * @param array $allowed_icon_html Allowed HTML
668 *
669 * @return array
670 */
671 $allowed_icon_html = apply_filters(
672 'rtsb/core/allowed_icon_html',
673 [
674 'i' => [
675 'class' => true,
676 ],
677 'img' => [
678 'src' => true,
679 'alt' => true,
680 'width' => true,
681 'height' => true,
682 ],
683 'svg' => [
684 'class' => true,
685 'aria-hidden' => true,
686 'aria-labelledby' => true,
687 'role' => true,
688 'xmlns' => true,
689 'width' => true,
690 'height' => true,
691 'viewbox' => true,
692 'stroke' => true,
693 'fill' => true,
694 ],
695 'g' => [
696 'fill' => true,
697 ],
698 'title' => [
699 'title' => true,
700 ],
701 'path' => [
702 'd' => true,
703 'fill' => true,
704 'stroke' => true,
705 'stroke-width' => true,
706 'stroke-linecap' => true,
707 'stroke-linejoin' => true,
708 'fill-rule' => true,
709 'clip-rule' => true,
710 ],
711 ]
712 );
713
714 echo wp_kses( $data, $allowed_icon_html );
715 }
716
717 /**
718 * Prints HTMl.
719 *
720 * @param string $html HTML.
721 * @param bool $allHtml All HTML.
722 *
723 * @return void
724 */
725 public static function print_html( $html, $allHtml = false ) {
726 if ( ! $html ) {
727 return;
728 }
729 if ( $allHtml ) {
730 echo stripslashes_deep( $html ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
731 } else {
732 echo wp_kses_post( stripslashes_deep( $html ) );
733 }
734 }
735
736 /**
737 * Allowed HTML for wp_kses.
738 *
739 * @param string $level Tag level.
740 *
741 * @return mixed
742 */
743 public static function allowedHtml( $level = 'basic' ) {
744 $allowed_html = [];
745 // TODO:: Need Optimize.
746 switch ( $level ) {
747 case 'basic':
748 $allowed_html = [
749 'b' => [
750 'class' => [],
751 'id' => [],
752 ],
753 'i' => [
754 'class' => [],
755 'id' => [],
756 ],
757 'u' => [
758 'class' => [],
759 'id' => [],
760 ],
761 'br' => [
762 'class' => [],
763 'id' => [],
764 ],
765 'em' => [
766 'class' => [],
767 'id' => [],
768 ],
769 'span' => [
770 'class' => [],
771 'id' => [],
772 ],
773 'strong' => [
774 'class' => [],
775 'id' => [],
776 ],
777 'hr' => [
778 'class' => [],
779 'id' => [],
780 ],
781 'div' => [
782 'class' => [],
783 'id' => [],
784 ],
785 'a' => [
786 'href' => [],
787 'title' => [],
788 'class' => [],
789 'id' => [],
790 'target' => [],
791 ],
792 ];
793 break;
794
795 case 'advanced':
796 $allowed_html = [
797 'b' => [
798 'class' => [],
799 'id' => [],
800 ],
801 'i' => [
802 'class' => [],
803 'id' => [],
804 ],
805 'u' => [
806 'class' => [],
807 'id' => [],
808 ],
809 'br' => [
810 'class' => [],
811 'id' => [],
812 ],
813 'em' => [
814 'class' => [],
815 'id' => [],
816 ],
817 'span' => [
818 'class' => [],
819 'id' => [],
820 ],
821 'strong' => [
822 'class' => [],
823 'id' => [],
824 ],
825 'hr' => [
826 'class' => [],
827 'id' => [],
828 ],
829 'a' => [
830 'href' => [],
831 'title' => [],
832 'class' => [],
833 'id' => [],
834 'target' => [],
835 ],
836 'input' => [
837 'type' => [],
838 'name' => [],
839 'class' => [],
840 'value' => [],
841 ],
842 ];
843 break;
844
845 case 'image':
846 $allowed_html = [
847 'img' => [
848 'src' => [],
849 'data-src' => [],
850 'alt' => [],
851 'height' => [],
852 'width' => [],
853 'class' => [],
854 'id' => [],
855 'style' => [],
856 'srcset' => [],
857 'loading' => [],
858 'sizes' => [],
859 ],
860 'div' => [
861 'class' => [],
862 ],
863 ];
864 break;
865
866 case 'anchor':
867 $allowed_html = [
868 'a' => [
869 'href' => [],
870 'title' => [],
871 'class' => [],
872 'id' => [],
873 'style' => [],
874 ],
875 ];
876 break;
877
878 default:
879 // code...
880 break;
881 }
882
883 return $allowed_html;
884 }
885
886 /**
887 * Insert Some array element
888 *
889 * @param [type] $key The elements will insert nearby this key.
890 * @param [type] $main_array Original array.
891 * @param [type] $insert_array some element will insert in original array.
892 * @param boolean $is_after array insert position base on the key.
893 *
894 * @return array
895 */
896 public static function insert_controls( $key, $main_array, $insert_array, $is_after = false ) {
897 $index = array_search( $key, array_keys( $main_array ), true );
898 if ( 'integer' === gettype( $index ) ) {
899 if ( $is_after ) {
900 $index++;
901 }
902 $main_array = array_merge(
903 array_slice( $main_array, 0, $index ),
904 $insert_array,
905 array_slice( $main_array, $index )
906 );
907 }
908
909 return $main_array;
910 }
911
912 /**
913 * Image Sizes
914 *
915 * @return array
916 */
917 public static function get_image_sizes() {
918 global $_wp_additional_image_sizes;
919
920 $sizes = [];
921
922 foreach ( get_intermediate_image_sizes() as $_size ) {
923 if ( in_array( $_size, [ 'thumbnail', 'medium', 'large' ], true ) ) {
924 $sizes[ $_size ]['width'] = get_option( "{$_size}_size_w" );
925 $sizes[ $_size ]['height'] = get_option( "{$_size}_size_h" );
926 $sizes[ $_size ]['crop'] = (bool) get_option( "{$_size}_crop" );
927 } elseif ( isset( $_wp_additional_image_sizes[ $_size ] ) ) {
928 $sizes[ $_size ] = [
929 'width' => $_wp_additional_image_sizes[ $_size ]['width'],
930 'height' => $_wp_additional_image_sizes[ $_size ]['height'],
931 'crop' => $_wp_additional_image_sizes[ $_size ]['crop'],
932 ];
933 }
934 }
935
936 $imgSize = [];
937
938 foreach ( $sizes as $key => $img ) {
939 $imgSize[ $key ] = ucfirst( $key ) . " ({$img['width']}*{$img['height']})";
940 }
941
942 $imgSize['full'] = esc_html__( 'Full size', 'shopbuilder' );
943 $imgSize['rtsb_custom'] = esc_html__( 'Custom image size', 'shopbuilder' );
944
945 return $imgSize;
946 }
947
948 /**
949 * Free Layouts
950 *
951 * @return array
952 */
953 public static function free_layouts() {
954 $layouts = [
955 'grid-layout1' => esc_html__( 'Grid Layout 1', 'shopbuilder' ),
956 'grid-layout2' => esc_html__( 'Grid Layout 2', 'shopbuilder' ),
957 'list-layout1' => esc_html__( 'List Layout 1', 'shopbuilder' ),
958 'list-layout2' => esc_html__( 'List Layout 2', 'shopbuilder' ),
959 'slider-layout1' => esc_html__( 'Slider Layout 1', 'shopbuilder' ),
960 'slider-layout2' => esc_html__( 'Slider Layout 2', 'shopbuilder' ),
961 'category-single-layout1' => esc_html__( 'Category Single Layout 1', 'shopbuilder' ),
962 'category-layout1' => esc_html__( 'Category Layout 1', 'shopbuilder' ),
963 'category-layout2' => esc_html__( 'Category Layout 2', 'shopbuilder' ),
964 'category-layout3' => esc_html__( 'Category Layout 2', 'shopbuilder' ),
965 ];
966
967 return apply_filters( 'rtsb/elements/elementor/free_layouts', $layouts );
968 }
969
970 /**
971 * Get all terms by taxonomy
972 *
973 * @param string $taxonomy Taxonomy name.
974 * @param bool $placeholder Placeholder..
975 *
976 * @return array
977 */
978 public static function get_all_terms( $taxonomy, $placeholder = false ) {
979 $terms = [];
980
981 if ( empty( $taxonomy ) ) {
982 return $terms;
983 }
984
985 $termList = get_terms( [ $taxonomy ], [ 'hide_empty' => 0 ] );
986
987 if ( is_array( $termList ) && ! empty( $termList ) && empty( $termList['errors'] ) ) {
988 if ( $placeholder ) {
989 $terms = [
990 'all' => __( 'All Products', 'shopbuilder' ),
991 ];
992 }
993
994 foreach ( $termList as $term ) {
995 $terms[ $term->term_id ] = esc_html( $term->name );
996 }
997 }
998
999 return $terms;
1000 }
1001
1002 /**
1003 * Get all terms by attributes
1004 *
1005 * @return array
1006 */
1007 public static function get_all_attributes() {
1008 $terms = [];
1009 $termList = [];
1010
1011 $attributes = wc_get_attribute_taxonomies();
1012
1013 if ( $attributes ) {
1014 foreach ( $attributes as $tax ) {
1015 if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) ) {
1016 $termList[ $tax->attribute_name ] = get_terms( wc_attribute_taxonomy_name( $tax->attribute_name ), 'orderby=name&hide_empty=0' );
1017 }
1018 }
1019 }
1020
1021 if ( ! empty( $termList ) && empty( $termList['errors'] ) && is_array( $termList ) ) {
1022 foreach ( $termList as $name => $atts ) {
1023 foreach ( $atts as $term ) {
1024 $terms[ $term->term_id ] = esc_html( ucwords( str_replace( '-', ' ', $name ) ) . ' - ' . $term->name );
1025 }
1026 }
1027 }
1028
1029 return $terms;
1030 }
1031
1032 /**
1033 * Get all attributes name
1034 *
1035 * @return array
1036 */
1037 public static function get_all_attributes_name() {
1038 $attributes_name = [];
1039
1040 $attributes = wc_get_attribute_taxonomies();
1041
1042 if ( $attributes ) {
1043 foreach ( $attributes as $tax ) {
1044 if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) ) {
1045 $attributes_name[ wc_attribute_taxonomy_name( $tax->attribute_name ) ] = ucwords( $tax->attribute_name );
1046 }
1047 }
1048 }
1049
1050 return $attributes_name;
1051 }
1052
1053 /**
1054 * Get User list
1055 *
1056 * @return array
1057 */
1058 public static function get_users() {
1059 $users = [];
1060 $u = get_users();
1061
1062 if ( ! empty( $u ) ) {
1063 foreach ( $u as $user ) {
1064 $users[ $user->ID ] = $user->display_name;
1065 }
1066 }
1067
1068 return $users;
1069 }
1070
1071 /**
1072 * Get Taxonomy List.
1073 *
1074 * @return array
1075 */
1076 public static function get_tax_list() {
1077 return apply_filters(
1078 'rtsb/elements/tax_list',
1079 [
1080 'product_cat' => esc_html__( 'Product Category', 'shopbuilder' ),
1081 ]
1082 );
1083 }
1084
1085 /**
1086 * Get Category Query List.
1087 *
1088 * @return array
1089 */
1090 public static function get_cat_list() {
1091 return [
1092 'all' => esc_html__( 'All Categories', 'shopbuilder' ),
1093 'specific_parent' => esc_html__( 'Sub-Categories by Parent', 'shopbuilder' ),
1094 'cat_ids' => esc_html__( 'Select by ID', 'shopbuilder' ),
1095 'selection' => esc_html__( 'Manual Selection', 'shopbuilder' ),
1096 ];
1097 }
1098
1099 /**
1100 * Get Term List.
1101 *
1102 * @param string $taxonomy Taxonomy.
1103 * @param bool $first_term First term.
1104 * @param bool $only_parents Only parent terms.
1105 * @param bool $return_slug Return with slug.
1106 *
1107 * @return int|array
1108 */
1109 public static function get_terms( $taxonomy, $first_term = false, $only_parents = false, $return_slug = false ) {
1110 // TODO:: Return Slug always true for all settings.
1111 $term_list = [];
1112 $args = [
1113 'taxonomy' => $taxonomy,
1114 'hide_empty' => false,
1115 ];
1116
1117 if ( $only_parents ) {
1118 $args['parent'] = 0;
1119 }
1120
1121 $terms = get_terms( $args );
1122
1123 if ( empty( $terms ) ) {
1124 return [ esc_html__( 'Nothing found', 'shopbuilder' ) ];
1125 }
1126
1127 foreach ( $terms as $term ) {
1128 if ( $return_slug ) {
1129 $term_list[ $term->slug ] = $term->name;
1130 } else {
1131 $term_list[ $term->term_id ] = $term->name;
1132 }
1133 }
1134
1135 if ( $first_term ) {
1136 return array_keys( $term_list )[0];
1137 } else {
1138 return $term_list;
1139 }
1140 }
1141
1142 /**
1143 * Get product rating.
1144 *
1145 * @return string|void
1146 */
1147 public static function get_product_rating_html() {
1148 global $product;
1149
1150 $html = '';
1151 $rating_count = $product->get_rating_count();
1152 $average = $product->get_average_rating();
1153
1154 if ( ! $rating_count || empty( wc_get_rating_html( $average, $rating_count ) ) ) {
1155 return $html;
1156 }
1157
1158 $html .= '<div class="product-rating">';
1159 $html .= wc_get_rating_html( $average, $rating_count );
1160 // TODO:: Disable Rating Count option need to apply.
1161 $html .= ! empty( $html ) ? '<span class="count">(' . $average . ')</span>' : '';
1162 $html .= '</div>';
1163
1164 self::print_html( $html, true );
1165 }
1166
1167 /**
1168 * Text truncation.
1169 *
1170 * @param string $text_to_truncate Text.
1171 * @param int $limit Limit.
1172 * @param string $after After text.
1173 *
1174 * @return string
1175 */
1176 public static function text_truncation( $text_to_truncate, $limit, $after = '&#8230;' ) {
1177 if ( empty( $limit ) ) {
1178 return $text_to_truncate;
1179 }
1180
1181 $limit++;
1182
1183 $text = '';
1184
1185 if ( mb_strlen( $text_to_truncate ) > $limit ) {
1186 $subex = mb_substr( wp_strip_all_tags( $text_to_truncate ), 0, $limit );
1187 $exwords = explode( ' ', $subex );
1188 $excut = - ( mb_strlen( $exwords[ count( $exwords ) - 1 ] ) );
1189
1190 if ( $excut < 0 ) {
1191 $text .= mb_substr( $subex, 0, $excut ) . $after;
1192 } else {
1193 $text .= $subex . $after;
1194 }
1195 } else {
1196 $text .= $text_to_truncate;
1197 }
1198
1199 return $text;
1200 }
1201
1202 /**
1203 * Promo Badge HTML
1204 *
1205 * @param string $text Text.
1206 * @param string $class Class.
1207 *
1208 * @return void
1209 */
1210 public static function get_badge_html( $text, $class = 'fill' ) {
1211 if ( empty( $text ) ) {
1212 return;
1213 }
1214 ob_start();
1215 ?>
1216
1217 <ul class="rtsb-promotion-list">
1218 <li class="rtsb-promotion-list-item">
1219 <span
1220 class="rtsb-tag-<?php echo ! empty( $class ) ? esc_attr( $class ) : ''; ?>"><?php echo esc_html( $text ); ?></span>
1221 </li>
1222 </ul>
1223
1224 <?php
1225 self::print_html( ob_get_clean() );
1226 }
1227
1228 /**
1229 * Categories HTML
1230 *
1231 * @param int $id Product ID.
1232 * @param string $class Custom class.
1233 *
1234 * @return void|string
1235 */
1236 public static function get_categories_list( $id, $class = 'rtsb-category-outline' ) {
1237 if ( empty( $id ) ) {
1238 return '';
1239 }
1240
1241 ob_start();
1242 ?>
1243
1244 <ul class="rtsb-category-list <?php echo esc_attr( $class ); ?>">
1245 <?php
1246 self::print_html(
1247 wc_get_product_category_list(
1248 $id,
1249 '</li><li class="rtsb-category-list-item">',
1250 '<li class="rtsb-category-list-item">',
1251 '</li>'
1252 )
1253 );
1254 ?>
1255 </ul>
1256
1257 <?php
1258 self::print_html( ob_get_clean() );
1259 }
1260
1261
1262 /**
1263 * Get Featured Image HTML.
1264 *
1265 * @param string $type Image type.
1266 * @param int $post_id Post ID.
1267 * @param string $f_img_size Image size.
1268 * @param null $default_img_id Default image ID.
1269 * @param array $custom_img_size Custom image size.
1270 * @param bool $lazy Lazy load check.
1271 * @param bool $hover Hover image.
1272 * @param bool $gallery Gallery image.
1273 *
1274 * @return string|null
1275 */
1276 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 ) {
1277 $img_html = null;
1278 $attachment_id = null;
1279 $c_size = false;
1280 $hover_class = '';
1281 $post_title = '';
1282
1283 if ( 'rtsb_custom' === $f_img_size ) {
1284 $f_img_size = 'full';
1285 $c_size = true;
1286 }
1287
1288 if ( ! rtsb()->has_pro() ) {
1289 $gallery = false;
1290 }
1291
1292 if ( $hover ) {
1293 $a_id = $post_id;
1294 $hover_class = ' rtsb-img-hover';
1295 } elseif ( $gallery ) {
1296 $a_id = $post_id;
1297 } else {
1298 if ( 'product' === $type ) {
1299 $a_id = get_post_thumbnail_id( $post_id );
1300 $post_title = get_the_title( $post_id );
1301 } elseif ( 'category' === $type ) {
1302 $a_id = get_term_meta( $post_id, 'thumbnail_id', true );
1303 $post_title = get_term( $post_id )->name;
1304 } else {
1305 $a_id = $default_img_id;
1306 }
1307 }
1308
1309 $img_alt = trim( wp_strip_all_tags( get_post_meta( $a_id, '_wp_attachment_image_alt', true ) ) );
1310 $alt_tag = ! empty( $img_alt ) ? $img_alt : wp_strip_all_tags( $post_title );
1311 $lazy_class = $lazy ? ' swiper-lazy' : '';
1312 $attr = [
1313 'class' => 'img-responsive rtsb-product-image' . $lazy_class . $hover_class,
1314 'alt' => $alt_tag,
1315 ];
1316
1317 if ( $a_id ) {
1318 $img_html = wp_get_attachment_image( $a_id, $f_img_size, false, $attr );
1319 $attachment_id = $a_id;
1320 }
1321
1322 if ( ! $img_html && $default_img_id ) {
1323 $img_html = wp_get_attachment_image( $default_img_id, $f_img_size, false, $attr );
1324 $attachment_id = $default_img_id;
1325 }
1326
1327 if ( $img_html && $c_size ) {
1328 preg_match( '@src="([^"]+)"@', $img_html, $match );
1329 $img_src = array_pop( $match );
1330 $w = ! empty( $custom_img_size['width'] ) ? absint( $custom_img_size['width'] ) : null;
1331 $h = ! empty( $custom_img_size['height'] ) ? absint( $custom_img_size['height'] ) : null;
1332 $c = ! empty( $custom_img_size['crop'] ) && 'soft' === $custom_img_size['crop'] ? false : true;
1333
1334 if ( $w && $h ) {
1335 $image = self::image_resize( $img_src, $w, $h, $c, false );
1336
1337 if ( ! empty( $image ) ) {
1338 [ $src, $width, $height ] = $image;
1339
1340 $hwstring = image_hwstring( $width, $height );
1341 $attachment = get_post( $attachment_id );
1342 $attr = apply_filters( 'wp_get_attachment_image_attributes', $attr, $attachment, $f_img_size );
1343
1344 if ( $lazy ) {
1345 $attr['data-src'] = $src;
1346 } else {
1347 $attr['src'] = $src;
1348 }
1349
1350 $attr = array_map( 'esc_attr', $attr );
1351 $img_html = rtrim( "<img $hwstring" );
1352
1353 foreach ( $attr as $name => $value ) {
1354 $img_html .= " $name=" . '"' . $value . '"';
1355 }
1356
1357 $img_html .= ' />';
1358 }
1359 }
1360 }
1361
1362 if ( ! $img_html ) {
1363 $hwstring = image_hwstring( 160, 160 );
1364 $attr = isset( $attr['src'] ) ? apply_filters( 'wp_get_attachment_image_attributes', $attr, false, $f_img_size ) : [];
1365 $attr['class'] = 'default-img';
1366 $attr['src'] = esc_url( rtsb()->get_assets_uri( 'images/demo.png' ) );
1367 $attr['alt'] = esc_html__( 'Default Image', 'shopbuilder' );
1368 $img_html = rtrim( "<img $hwstring" );
1369
1370 foreach ( $attr as $name => $value ) {
1371 $img_html .= " $name=" . '"' . $value . '"';
1372 }
1373
1374 $img_html .= ' />';
1375 }
1376
1377 if ( $lazy ) {
1378 $img_html = $img_html . '<div class="swiper-lazy-preloader swiper-lazy-preloader"></div>';
1379 }
1380
1381 return $img_html;
1382 }
1383
1384 /**
1385 * Call the Image resize model for resize function
1386 *
1387 * @param string $url URL.
1388 * @param int $width Width.
1389 * @param int $height Height.
1390 * @param string $crop Crop.
1391 * @param bool|true $single Single.
1392 * @param bool|false $upscale Upscale.
1393 *
1394 * @return array|bool|string
1395 */
1396 public static function image_resize( $url, $width = null, $height = null, $crop = null, $single = true, $upscale = false ) {
1397 $rtResize = new ReSizer();
1398
1399 return $rtResize->process( $url, $width, $height, $crop, $single, $upscale );
1400 }
1401
1402 /**
1403 * Get Product Image
1404 *
1405 * @param string $f_image Featured Image.
1406 * @param string $h_image Hover Image.
1407 *
1408 * @return void
1409 */
1410 public static function get_product_image( $f_image, $h_image = null ) {
1411 if ( empty( $f_image ) ) {
1412 return;
1413 }
1414
1415 echo wp_kses( $f_image, self::allowedHtml( 'image' ) );
1416
1417 if ( ! empty( $h_image ) ) {
1418 echo wp_kses( $h_image, self::allowedHtml( 'image' ) );
1419 }
1420 }
1421
1422 /**
1423 * Post Custom Field value.
1424 *
1425 * @param int $post_id Post id.
1426 * @param string $field_key Custom Field Key.
1427 * @param string $field_fallback FallBack text.
1428 *
1429 * @return string|void
1430 */
1431 public static function get_post_custom_field_value( $post_id, $field_key = '', $field_fallback = '' ) {
1432 if ( ! $post_id || ! $field_key ) {
1433 return;
1434 }
1435 $field_value = get_post_meta( $post_id, $field_key, true );
1436 if ( empty( $field_value ) ) {
1437 $field_value = ! empty( $field_fallback ) ? $field_fallback : $field_value;
1438 }
1439 $field_value = apply_filters( 'rtsb/get_post_custom_field_value/' . $field_key, $field_value, $field_key );
1440
1441 return sprintf( '<span class="rtsb-woo-custom-field">%s</span>', $field_value );
1442 }
1443
1444 /**
1445 * Elementor Icon
1446 *
1447 * @param array $control Elementor Control array.
1448 * @param string $class Custom class.
1449 * @param string $builder Builder name.
1450 *
1451 * @return string
1452 */
1453 public static function icons_manager( $control, $class = '', $builder = 'elementor' ): string {
1454 $attributes = [
1455 'aria-hidden' => 'true',
1456 ];
1457
1458 if ( ! empty( $class ) ) {
1459 $attributes['class'] = esc_attr( $class );
1460 }
1461
1462 ob_start();
1463
1464 if ( defined( 'ELEMENTOR_VERSION' ) && ! empty( $control ) && 'elementor' === $builder ) {
1465 Icons_Manager::render_icon( $control, $attributes );
1466 }
1467
1468 return ob_get_clean();
1469 }
1470
1471 /**
1472 * Get product swatches.
1473 *
1474 * @param string $type Swatch type.
1475 *
1476 * @return void
1477 */
1478 public static function get_product_swatches( $type ) {
1479 ?>
1480 <div class="rtsb-swatches <?php echo esc_attr( $type ); ?>-layout">
1481 <?php
1482 do_action( 'rtwpvs_show_archive_variation' );
1483 ?>
1484 </div>
1485 <?php
1486 }
1487
1488 /**
1489 * Get sale badge
1490 *
1491 * @param string $type Badge type.
1492 * @param string $text Badge text.
1493 * @param string $out_of_stock_text Out of stock text.
1494 *
1495 * @return string
1496 */
1497 public static function get_sale_badge( $type, $text, $out_of_stock_text ) {
1498 global $product;
1499
1500 if ( ! $product->is_in_stock() ) {
1501 return $out_of_stock_text;
1502 }
1503
1504 if ( ! $product->is_on_sale() ) {
1505 return '';
1506 }
1507
1508 $badge_text = '';
1509 $percentage = null;
1510 $max_percentage = '';
1511
1512 if ( $product->is_type( 'simple' ) ) {
1513 $max_percentage = ( ( $product->get_regular_price() - $product->get_sale_price() ) / $product->get_regular_price() ) * 100;
1514 } elseif ( $product->is_type( 'variable' ) ) {
1515 $max_percentage = 0;
1516
1517 foreach ( $product->get_children() as $child_id ) {
1518
1519 $variation = wc_get_product( $child_id );
1520
1521 $price = $variation->get_regular_price();
1522 $sale = $variation->get_sale_price();
1523
1524 if ( 0 !== $price && ! empty( $sale ) ) {
1525 $percentage = ( $price - $sale ) / $price * 100;
1526 }
1527
1528 if ( $percentage > $max_percentage ) {
1529 $max_percentage = $percentage;
1530 }
1531 }
1532 }
1533
1534 if ( $max_percentage > 0 ) {
1535 $badge_text = '-' . round( $max_percentage ) . '%';
1536 }
1537
1538 if ( 'text' === $type ) {
1539 $badge_text = $text;
1540 }
1541
1542 return $badge_text;
1543 }
1544
1545 /**
1546 * Pagination
1547 *
1548 * @param string $pages Pages.
1549 * @param integer $range Range.
1550 * @param boolean $ajax Ajax.
1551 *
1552 * @return string
1553 */
1554 public static function custom_pagination( $pages = '', $range = 4, $ajax = false ) {
1555 $html = null;
1556 $showitems = ( $range * 2 ) + 1;
1557
1558 global $paged;
1559
1560 if ( is_front_page() ) {
1561 $paged = ( get_query_var( 'page' ) ) ? get_query_var( 'page' ) : 1;
1562 } else {
1563 $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
1564 }
1565
1566 if ( empty( $paged ) ) {
1567 $paged = 1;
1568 }
1569
1570 if ( '' === $pages ) {
1571 global $wp_query;
1572
1573 $pages = $wp_query->max_num_pages;
1574
1575 if ( ! $pages ) {
1576 $pages = 1;
1577 }
1578 }
1579
1580 $ajaxClass = null;
1581 $dataAttr = null;
1582
1583 if ( $ajax ) {
1584 $ajaxClass = ' rtsb-pagination-ajax';
1585 $dataAttr = "data-paged='1'";
1586 }
1587
1588 if ( 1 !== $pages ) {
1589 $html .= '<div class="rtsb-pagination' . $ajaxClass . '" ' . $dataAttr . '>';
1590 $html .= '<ul class="pagination-list">';
1591
1592 if ( $paged > 2 && $paged > $range + 1 && $showitems < $pages ) {
1593 $html .= "<li><a data-paged='1' href='" . get_pagenum_link( 1 ) . "' aria-label='First'>&laquo;</a></li>";
1594 }
1595
1596 if ( $paged > 1 && $showitems < $pages ) {
1597 $p = $paged - 1;
1598 $html .= "<li><a data-paged='{$p}' href='" . get_pagenum_link( $p ) . "' aria-label='Previous'>&lsaquo;</a></li>";
1599 }
1600
1601 for ( $i = 1; $i <= $pages; $i++ ) {
1602 if ( 1 != $pages && ( ! ( $i >= $paged + $range + 1 || $i <= $paged - $range - 1 ) || $pages <= $showitems ) ) {
1603 $html .= ( $paged == $i ) ? '<li class="active"><span>' . $i . '</span></li>' : "<li><a data-paged='{$i}' href='" . get_pagenum_link( $i ) . "'>" . $i . '</a></li>';
1604 }
1605 }
1606
1607 if ( $paged < $pages && $showitems < $pages ) {
1608 $p = $paged + 1;
1609 $html .= "<li><a data-paged='{$p}' href=\"" . get_pagenum_link( $paged + 1 ) . "\" aria-label='Next'>&rsaquo;</a></li>";
1610 }
1611
1612 if ( $paged < $pages - 1 && $paged + $range - 1 < $pages && $showitems < $pages ) {
1613 $html .= "<li><a data-paged='{$pages}' href='" . get_pagenum_link( $pages ) . "' aria-label='Last'>&raquo;</a></li>";
1614 }
1615
1616 $html .= '</ul>';
1617 $html .= '</div>';
1618 }
1619
1620 return $html;
1621 }
1622
1623 /**
1624 * Action Buttons HTMl
1625 *
1626 * @param array $items Items.
1627 * @param array $ajax_cart Ajax cart HTML.
1628 * @param string $preset Button preset.
1629 * @param array $position Position.
1630 * @param string $placement Placement.
1631 *
1632 * @return void|string
1633 */
1634 public static function get_formatted_action_buttons( $items, $ajax_cart = '', $preset = 'preset1', $position = 'above', $placement = 'top' ) {
1635 if ( empty( $items ) ) {
1636 return;
1637 }
1638
1639 $html = '';
1640 $class = '';
1641 $args = [ $items, $ajax_cart, $preset, $position, $placement ];
1642
1643 if ( ( 'top' === $placement && 'after' === $position ) || ( 'bottom' === $placement && 'above' === $position ) ) {
1644 return apply_filters( 'rtsb/elements/elementor/formatted_action_buttons', $html, $args );
1645 }
1646
1647 if ( 'preset2' === $preset ) {
1648 $class = 'rtsb-action-buttons-vertical vertical-delay-effect ' . $preset;
1649 } elseif ( 'preset4' === $preset ) {
1650 $class = 'rtsb-action-buttons-vertical rtsb-action-buttons-vertical-left vertical-delay-effect ' . $preset;
1651 } elseif ( 'preset1' === $preset || 'preset3' === $preset ) {
1652 $class = 'rtsb-action-buttons-cart-box-width-auto horizontal-floating-btn ' . $preset;
1653 }
1654
1655 if ( 'after' === $position && 'preset1' === $preset ) {
1656 $class .= ' after-content';
1657 }
1658
1659 if ( 'preset3' === $preset ) {
1660 $html .= '<div class="rtsb-action-buttons top-part ' . esc_attr( $preset ) . '">';
1661 $html .= '<ul class="rtsb-action-button-list">';
1662
1663 ob_start();
1664 /**
1665 * Additional formatted action buttons hook.
1666 */
1667 do_action( 'rtsb/elements/elementor/additional_action_buttons', $items );
1668 $html .= ob_get_clean();
1669
1670 // $html .= self::get_action_button_by_type( $items, 'quick_checkout' );
1671 $html .= self::get_action_button_by_type( $items, 'wishlist' );
1672 $html .= self::get_action_button_by_type( $items, 'compare' );
1673 $html .= self::get_action_button_by_type( $items, 'quick_view' );
1674 $html .= '</ul>';
1675 $html .= '</div>';
1676 $html .= '<div class="rtsb-action-buttons bottom-part ' . esc_attr( $preset ) . '">';
1677 $html .= '<ul class="rtsb-action-button-list">';
1678 $html .= self::get_action_button_by_type( $items, 'add_to_cart', $ajax_cart );
1679 $html .= '</ul>';
1680 $html .= '</div>';
1681 } elseif ( 'preset1' === $preset || 'preset2' === $preset || 'preset4' === $preset ) {
1682 $html .= '<div class="rtsb-action-buttons ' . esc_attr( $class ) . '">';
1683 $html .= '<ul class="rtsb-action-button-list">';
1684 $html .= self::get_action_button_by_type( $items, 'add_to_cart', $ajax_cart );
1685 // $html .= self::get_action_button_by_type( $items, 'quick_checkout' );
1686
1687 ob_start();
1688 /**
1689 * Additional formatted action buttons hook.
1690 */
1691 do_action( 'rtsb/elements/elementor/additional_action_buttons', $items );
1692 $html .= ob_get_clean();
1693
1694 $html .= self::get_action_button_by_type( $items, 'wishlist' );
1695 $html .= self::get_action_button_by_type( $items, 'compare' );
1696 $html .= self::get_action_button_by_type( $items, 'quick_view' );
1697 $html .= '</ul>';
1698 $html .= '</div>';
1699 }
1700
1701 return apply_filters( 'rtsb/elements/elementor/formatted_action_buttons', $html, $args );
1702 }
1703
1704 /**
1705 * Get Action Button HTML
1706 *
1707 * @param array $items Items.
1708 * @param string $type Button type.
1709 * @param string $cart_html Ajax cart HTML.
1710 * @param string $wrapper Wrapper tag.
1711 *
1712 * @return void|string
1713 */
1714 public static function get_action_button_by_type( $items, $type, $cart_html = '', $wrapper = 'li' ) {
1715 if ( ! in_array( $type, $items, true ) ) {
1716 return;
1717 }
1718
1719 $html = '';
1720 $class = 'rtsb-action-button-item';
1721
1722 if ( 'add_to_cart' === $type ) {
1723 $class .= ' rtsb-cart' . ( empty( $cart_html ) ? esc_attr( ' no-cart-button' ) : '' );
1724 } else {
1725 $class .= ' rtsb-' . esc_attr( str_replace( '_', '-', $type ) );
1726 }
1727
1728 $html .= '<' . esc_attr( $wrapper ) . ' class="' . esc_attr( $class ) . '">';
1729
1730 if ( ( 'add_to_cart' === $type ) && ( ! empty( $cart_html ) ) ) {
1731 $html .= $cart_html;
1732 } else {
1733 $html .= shortcode_exists( 'rtsb_' . $type . '_button' ) ? do_shortcode( '[rtsb_' . $type . '_button]' ) : null;
1734 }
1735
1736 $html .= '</' . esc_attr( $wrapper ) . '>';
1737
1738 return apply_filters( 'rtsb/elements/elementor/get_action_button_by_type', $html );
1739 }
1740
1741 /**
1742 * Social Share Platforms.
1743 *
1744 * @return mixed|null
1745 */
1746 public static function social_share_platforms_list() {
1747 return apply_filters(
1748 'rtsb/settings/social_share/platforms',
1749 [
1750 [
1751 'value' => 'facebook',
1752 'label' => esc_html__( 'Facebook', 'shopbuilder' ),
1753 ],
1754 [
1755 'value' => 'twitter',
1756 'label' => esc_html__( 'Twitter', 'shopbuilder' ),
1757 ],
1758 [
1759 'value' => 'linkedin',
1760 'label' => esc_html__( 'Linkedin', 'shopbuilder' ),
1761 ],
1762 [
1763 'value' => 'pinterest',
1764 'label' => esc_html__( 'Pinterest', 'shopbuilder' ),
1765 ],
1766 [
1767 'value' => 'skype',
1768 'label' => esc_html__( 'Skype', 'shopbuilder' ),
1769 ],
1770 [
1771 'value' => 'whatsapp',
1772 'label' => esc_html__( 'Whatsapp', 'shopbuilder' ),
1773 ],
1774 [
1775 'value' => 'reddit',
1776 'label' => esc_html__( 'Reddit', 'shopbuilder' ),
1777 ],
1778 [
1779 'value' => 'telegram',
1780 'label' => esc_html__( 'Telegram', 'shopbuilder' ),
1781 ],
1782 ]
1783 );
1784 }
1785
1786 /**
1787 * Get Social Share link HTML.
1788 *
1789 * @param int $id Post ID.
1790 * @param array $types Preset type.
1791 * @param string $preset Style type.
1792 * @param boolean $show_icon Show icon.
1793 * @param boolean $show_text Show text.
1794 *
1795 * @return string
1796 */
1797 public static function get_social_share_html( int $id, array $types, string $preset = 'default', $show_icon = true, $show_text = true ) {
1798 $attr = [ 'postid' => $id ];
1799 $output = '';
1800
1801 if ( empty( $types ) ) {
1802 return $output;
1803 }
1804
1805 foreach ( $types as $type ) {
1806 $link = [];
1807 $link['type'] = $type['share_items'];
1808 $link['class'] = '';
1809 $link['img'] = apply_filters( 'rtsb/elements/share/default_img', '', $id, $link );
1810
1811 if ( 'site' === $id ) {
1812 $link['url'] = home_url();
1813 $link['title'] = wp_strip_all_tags( get_bloginfo( 'name' ) );
1814 } elseif ( 0 === strpos( $id, 'http' ) ) {
1815 $link['url'] = $id;
1816 $link['title'] = '';
1817 } else {
1818 $link['url'] = get_permalink( $id );
1819 $link['title'] = wp_strip_all_tags( get_the_title( $id ) );
1820
1821 if ( has_post_thumbnail( $id ) ) {
1822 $link['img'] = wp_get_attachment_image_url( get_post_thumbnail_id( $id ), 'full' );
1823 }
1824
1825 $link['img'] = apply_filters( 'rtsb/elements/share/single_img', $link['img'], $id, $link );
1826 }
1827
1828 $link['url'] = apply_filters( 'rtsb/elements/share/url', $link['url'], $link );
1829
1830 switch ( $type['share_items'] ) {
1831 case 'facebook':
1832 $link['link'] = esc_url( 'https://www.facebook.com/sharer/sharer.php?u=' . $link['url'] . '&display=popup&ref=plugin&src=share_button' );
1833 $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>';
1834 $link['attr_title'] = esc_html__( 'Share on Facebook', 'shopbuilder' );
1835 $link['social_network'] = 'Facebook';
1836 $link['social_action'] = 'Share';
1837 break;
1838 case 'twitter':
1839 $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'] );
1840 $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>';
1841 $link['attr_title'] = esc_html__( 'Share on Twitter', 'shopbuilder' );
1842 $link['social_network'] = 'Twitter';
1843 $link['social_action'] = 'Tweet';
1844 break;
1845 case 'pinterest':
1846 $link['link'] = esc_url( 'https://pinterest.com/pin/create/button/?url=' . $link['url'] . '&media=' . $link['img'] . '&description=' . $link['title'] );
1847 $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>';
1848 $link['attr_title'] = esc_html__( 'Share on Pinterest', 'shopbuilder' );
1849 $link['social_network'] = 'Pinterest';
1850 $link['social_action'] = 'Pin';
1851 break;
1852 case 'linkedin':
1853 $link['link'] = esc_url( 'https://www.linkedin.com/shareArticle?url=' . $link['url'] . '&title=' . $link['title'] );
1854 $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>';
1855 $link['attr_title'] = esc_html__( 'Share on LinkedIn', 'shopbuilder' );
1856 $link['social_network'] = 'LinkedIn';
1857 $link['social_action'] = 'Share';
1858 break;
1859 case 'skype':
1860 $link['link'] = esc_url( 'https://web.skype.com/share?url=' . $link['url'] );
1861 $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>';
1862 $link['attr_title'] = esc_html__( 'Share on Skype', 'shopbuilder' );
1863 $link['social_network'] = 'Skype';
1864 $link['social_action'] = 'Skype';
1865 break;
1866 case 'whatsapp':
1867 $link['link'] = esc_url( 'https://wa.me/?text=' . $link['title'] . ' ' . $link['url'] );
1868 $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>';
1869 $link['attr_title'] = esc_html__( 'Share on Whatsapp', 'shopbuilder' );
1870 $link['social_network'] = 'Whatsapp';
1871 $link['social_action'] = 'Share';
1872 break;
1873 case 'reddit':
1874 $link['link'] = esc_url( 'https://reddit.com/submit?url=' . $link['url'] . '&title=' . $link['title'] );
1875 $link['icon'] = '<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><title>ionicons-v5_logos</title><path d="M324,256a36,36,0,1,0,36,36A36,36,0,0,0,324,256Z"/><circle cx="188" cy="292" r="36" transform="translate(-97.43 94.17) rotate(-22.5)"/><path d="M496,253.77c0-31.19-25.14-56.56-56-56.56a55.72,55.72,0,0,0-35.61,12.86c-35-23.77-80.78-38.32-129.65-41.27l22-79L363.15,103c1.9,26.48,24,47.49,50.65,47.49,28,0,50.78-23,50.78-51.21S441,48,413,48c-19.53,0-36.31,11.19-44.85,28.77l-90-17.89L247.05,168.4l-4.63.13c-50.63,2.21-98.34,16.93-134.77,41.53A55.38,55.38,0,0,0,72,197.21c-30.89,0-56,25.37-56,56.56a56.43,56.43,0,0,0,28.11,49.06,98.65,98.65,0,0,0-.89,13.34c.11,39.74,22.49,77,63,105C146.36,448.77,199.51,464,256,464s109.76-15.23,149.83-42.89c40.53-28,62.85-65.27,62.85-105.06a109.32,109.32,0,0,0-.84-13.3A56.32,56.32,0,0,0,496,253.77ZM414,75a24,24,0,1,1-24,24A24,24,0,0,1,414,75ZM42.72,253.77a29.6,29.6,0,0,1,29.42-29.71,29,29,0,0,1,13.62,3.43c-15.5,14.41-26.93,30.41-34.07,47.68A30.23,30.23,0,0,1,42.72,253.77ZM390.82,399c-35.74,24.59-83.6,38.14-134.77,38.14S157,423.61,121.29,399c-33-22.79-51.24-52.26-51.24-83A78.5,78.5,0,0,1,75,288.72c5.68-15.74,16.16-30.48,31.15-43.79a155.17,155.17,0,0,1,14.76-11.53l.3-.21,0,0,.24-.17c35.72-24.52,83.52-38,134.61-38s98.9,13.51,134.62,38l.23.17.34.25A156.57,156.57,0,0,1,406,244.92c15,13.32,25.48,28.05,31.16,43.81a85.44,85.44,0,0,1,4.31,17.67,77.29,77.29,0,0,1,.6,9.65C442.06,346.77,423.86,376.24,390.82,399Zm69.6-123.92c-7.13-17.28-18.56-33.29-34.07-47.72A29.09,29.09,0,0,1,440,224a29.59,29.59,0,0,1,29.41,29.71A30.07,30.07,0,0,1,460.42,275.1Z"/><path d="M323.23,362.22c-.25.25-25.56,26.07-67.15,26.27-42-.2-66.28-25.23-67.31-26.27h0a4.14,4.14,0,0,0-5.83,0l-13.7,13.47a4.15,4.15,0,0,0,0,5.89h0c3.4,3.4,34.7,34.23,86.78,34.45,51.94-.22,83.38-31.05,86.78-34.45h0a4.16,4.16,0,0,0,0-5.9l-13.71-13.47a4.13,4.13,0,0,0-5.81,0Z"/></svg>';
1876 $link['attr_title'] = esc_html__( 'Share on Reddit', 'shopbuilder' );
1877 $link['social_network'] = 'Reddit';
1878 $link['social_action'] = 'Share';
1879 break;
1880 case 'telegram':
1881 $link['link'] = esc_url( 'https://telegram.me/share/url?text=' . $link['title'] . '&url=' . $link['url'] );
1882 $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>';
1883 $link['attr_title'] = esc_html__( 'Share on Telegram', 'shopbuilder' );
1884 $link['social_network'] = 'Telegram';
1885 $link['social_action'] = 'Share';
1886 break;
1887 }
1888
1889 $link['label'] = $type['share_text'];
1890 $link['target'] = '_blank';
1891 $link['rel'] = 'nofollow noopener noreferrer';
1892
1893 $data = '';
1894 $link = apply_filters( 'rtsb/elements/share/share_link', $link, $id, $preset );
1895 $icon = apply_filters( 'rtsb/elements/share/share_icon', $link['icon'], $preset );
1896 $target = ! empty( $link['target'] ) ? ' target="' . esc_attr( $link['target'] ) . '" ' : '';
1897 $rel = ! empty( $link['rel'] ) ? ' rel="' . esc_attr( $link['rel'] ) . '" ' : '';
1898 $attr_title = ! empty( $link['attr_title'] ) ? ' title="' . esc_attr( $link['attr_title'] ) . '" ' : '';
1899 $elements = [];
1900
1901 // Add classes.
1902 $css_classes = [
1903 'rtsb-share-btn',
1904 sanitize_html_class( $link['type'] ),
1905 ];
1906 $css_classes = array_merge( $css_classes, explode( ' ', $link['class'] ) );
1907 $css_classes = array_map( 'sanitize_html_class', $css_classes );
1908 $css_classes = implode( ' ', array_filter( $css_classes ) );
1909
1910 unset( $attr['pin-do'], $attr['action'] );
1911
1912 if ( 'pinterest' === $type['share_items'] ) {
1913 $attr['pin-do'] = 'none';
1914 }
1915
1916 if ( 'whatsapp' === $type['share_items'] ) {
1917 $attr['action'] = 'share/whatsapp/share';
1918 }
1919
1920 $attr = apply_filters( 'rtsb/elements/share/link_data', $attr, $link, $id );
1921
1922 if ( ! empty( $attr ) ) {
1923 foreach ( $attr as $key => $val ) {
1924 $data .= ' data-' . sanitize_html_class( $key ) . '="' . esc_attr( $val ) . '"';
1925 }
1926 }
1927
1928 $additional_attr = apply_filters( 'rtsb/elements/share/additional_attr', [], $link, $id, $preset );
1929
1930 if ( ! empty( $additional_attr ) ) {
1931 $attr_output = join( ' ', $additional_attr );
1932
1933 if ( ! empty( $data ) ) {
1934 $attr_output = ' ' . $attr_output;
1935 }
1936
1937 $data .= $attr_output;
1938 }
1939
1940 $elements['wrapper_start'] = sprintf(
1941 '<li class="rtsb-share-item"><a href="%s"%s%s%s class="%s"%s>',
1942 ! empty( $link['link'] ) ? esc_attr( $link['link'] ) : '',
1943 $attr_title,
1944 $target,
1945 $rel,
1946 $css_classes,
1947 $data
1948 );
1949 $elements['wrapper_end'] = '</a></li>';
1950
1951 $elements['icon'] = $show_icon ? '<span class="rtsb-share-icon">' . ( ! empty( $icon ) ? $icon : null ) . '</span>' : null;
1952 $elements['label'] = $show_text && ! empty( $link['label'] ) ? '<span class="rtsb-share-label">' . $link['label'] . '</span>' : null;
1953 $elements['icon_label'] = '<span class="rtsb-share-icon-label">' . $elements['icon'] . $elements['label'] . '</span>';
1954 $elements = apply_filters( 'rtsb/elements/share/output_elements', $elements, $link, $id );
1955
1956 $output .= $elements['wrapper_start'] . $elements['icon_label'] . $elements['wrapper_end'];
1957 }
1958
1959 return apply_filters( 'rtsb/elements/share/list_output', $output );
1960 }
1961
1962 /**
1963 * Social Share Platforms.
1964 *
1965 * @return mixed|null
1966 */
1967 public static function is_module_active( $module ) {
1968 $modulelist = ModuleList::instance()->get_data();
1969 if ( ! empty( $modulelist[ $module ]['active'] ) ) {
1970 return true;
1971 }
1972 }
1973
1974
1975 /***
1976 * Save Settings data
1977 *
1978 * @param $section_id
1979 * @param $block_id
1980 * @param $rawOptions
1981 *
1982 * @return array
1983 */
1984 public static function set_options( $section_id = '', $block_id = '', $rawOptions = [] ) {
1985 $section_id = ! empty( $section_id ) ? sanitize_text_field( wp_unslash( $section_id ) ) : '';
1986 $block_id = ! empty( $block_id ) ? sanitize_text_field( wp_unslash( $block_id ) ) : '';
1987 $rawOptions = ! empty( $rawOptions ) ? $rawOptions : [];
1988
1989 $results = [
1990 'status' => true,
1991 'message' => '',
1992 ];
1993 if ( ! $section_id || ! $block_id ) {
1994 $results['status'] = false;
1995 $results['message'] = esc_html__( 'Section , block or options may be empty', 'shopbuilder' );
1996
1997 return $results;
1998 }
1999 $sections = Settings::instance()->get_sections();
2000 if ( empty( $sections[ $section_id ] ) || empty( $sections[ $section_id ]['list'][ $block_id ] ) ) {
2001 $results['status'] = false;
2002 $results['message'] = esc_html__( 'No section or block found with given data', 'shopbuilder' );
2003
2004 return $results;
2005 }
2006
2007 $options = DataModel::source()->get_option( $section_id, [] );
2008 $changed = false;
2009 $fields = [];
2010 if ( isset( $sections[ $section_id ]['list'][ $block_id ]['fields'] ) && ! empty( $sections[ $section_id ]['list'][ $block_id ]['fields'] ) ) {
2011 $fields = $sections[ $section_id ]['list'][ $block_id ]['fields'];
2012 }
2013
2014 if ( empty( $fields ) ) {
2015 if ( isset( $rawOptions['active'] ) ) {
2016 $changed = true;
2017 $options[ $block_id ]['active'] = 'on' === $rawOptions['active'] ? 'on' : '';
2018 }
2019 } else {
2020 foreach ( $rawOptions as $raw_option_key => $raw_value ) {
2021 if ( $raw_option_key === 'active' ) {
2022 $changed = true;
2023 $options[ $block_id ]['active'] = $sections[ $section_id ]['list'][ $block_id ]['active'] = 'on' === $raw_value ? 'on' : '';
2024 } else {
2025 if ( isset( $fields[ $raw_option_key ] ) ) {
2026 $field = $fields[ $raw_option_key ];
2027 if ( $field['type'] === 'switch' ) {
2028 $value = 'on' === $raw_value ? 'on' : '';
2029 } elseif ( 'repeaters' === $field['type'] ) {
2030 $value = stripslashes_deep( $raw_value );
2031 } else {
2032 if ( ! empty( $field['multiple'] ) || in_array( $field['type'], [ 'checkbox', 'search_and_multi_select' ] ) ) {
2033
2034 if ( isset( $raw_value ) && is_array( $raw_value ) ) {
2035 if ( ! empty( $field['sanitize_fn'] ) && is_callable( $field['sanitize_fn'] ) ) {
2036 $value = array_map( $field['sanitize_fn'], $raw_value );
2037 } else {
2038 $value = array_map( 'sanitize_text_field', $raw_value );
2039 }
2040 } else {
2041 $value = [];
2042 }
2043 } else {
2044 if ( ! empty( $field['sanitize_fn'] ) && is_callable( $field['sanitize_fn'] ) ) {
2045 $value = $field['sanitize_fn']( $raw_value );
2046 } else {
2047 $value = sanitize_text_field( $raw_value );
2048 }
2049 }
2050 }
2051 $options[ $block_id ][ $raw_option_key ] = $sections[ $section_id ]['list'][ $block_id ]['fields'][ $raw_option_key ]['value'] = $value ?? null;
2052 $changed = true;
2053 }
2054 }
2055 }
2056 }
2057 if ( ! $changed ) {
2058 $results['status'] = false;
2059 $results['message'] = esc_html__( 'No changes found for update', 'shopbuilder' );
2060
2061 return $results;
2062 }
2063
2064 DataModel::source()->set_option( $section_id, $options );
2065
2066 $results['status'] = true;
2067 $results['message'] = esc_html__( 'Successfully Saved', 'shopbuilder' );
2068 $results['sections'] = $sections;
2069
2070 return $results;
2071 }
2072
2073 /***
2074 * @param $meta_key
2075 * @param $meta_value
2076 *
2077 * @return mixed|void
2078 *
2079 *
2080 * public static function get_post_id_by_meta_key_and_value( $meta_key, $meta_value ) {
2081 * if( ! $meta_key || ! $meta_value ){
2082 * return;
2083 * }
2084 * global $wpdb;
2085 * $prepare_guery = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '%s' and meta_value = '%d'", $meta_key, $meta_value );
2086 * $the_products = $wpdb->get_col( $prepare_guery );
2087 * if( count( $the_products ) > 0 ){
2088 * return $the_products[0];
2089 * }
2090 * return;
2091 * }
2092 */
2093
2094 public static function count_products_by_taxonomies( $terms, $taxonomy = 'product_cat' ) {
2095 if ( empty( $terms ) || ! is_array( $terms ) ) {
2096 return;
2097 }
2098
2099 $category_ids = array_map(
2100 function ( $name ) {
2101 return sanitize_title( $name );
2102 },
2103 $terms
2104 );
2105
2106 $args = [
2107 'post_type' => 'product',
2108 'posts_per_page' => - 1,
2109 'tax_query' => [
2110 [
2111 'taxonomy' => $taxonomy,
2112 'field' => 'term_id',
2113 'terms' => $category_ids,
2114 ],
2115 ],
2116 ];
2117
2118 $query = new \WP_Query( $args );
2119
2120 return $query->found_posts;
2121 }
2122
2123 /**
2124 * Check if product filters widget has ajax.
2125 *
2126 * @param string $page Page name.
2127 *
2128 * @return bool
2129 */
2130 public static function product_filters_has_ajax( $page ) {
2131 if ( empty( $page ) ) {
2132 return false;
2133 }
2134
2135 $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page );
2136 $elmap = ElementorDataMap::instance();
2137 $ajax = [];
2138
2139 foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) {
2140 $ajax[] = isset( $data['settings']['ajax_mode'] ) ? false : true;
2141 }
2142
2143 return ! empty( $ajax[0] );
2144 }
2145
2146 /**
2147 * Check if product has applied filter.
2148 *
2149 * @param string $page Page name.
2150 *
2151 * @return bool
2152 */
2153 public static function product_has_applied_filters( $page ) {
2154 if ( empty( $page ) ) {
2155 return false;
2156 }
2157
2158 $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page );
2159 $elmap = ElementorDataMap::instance();
2160 $ajax = [];
2161
2162 foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) {
2163 $ajax[] = ! isset( $data['settings']['active_filter'] );
2164
2165 }
2166
2167 return ! empty( $ajax[0] );
2168 }
2169
2170 /**
2171 * Get WooCommerce product categories.
2172 *
2173 * @param string|null $search_query The search string for category names.
2174 *
2175 * @return array An array of product categories with 'value' and 'label' keys.
2176 */
2177 public static function products_category_query( $search_query = null ) {
2178 global $wpdb;
2179
2180 $sql = "SELECT t.term_id, t.name
2181 FROM {$wpdb->terms} t
2182 JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
2183 WHERE tt.taxonomy = 'product_cat'";
2184
2185 if ( $search_query ) {
2186 $sql .= ' AND t.name LIKE %s';
2187 $prepared_sql = $wpdb->prepare( $sql, '%' . $wpdb->esc_like( $search_query ) . '%' ); // Escaping and wildcard
2188 } else {
2189 $prepared_sql = $sql; // No need for placeholders
2190 }
2191
2192 $results = $wpdb->get_results( $prepared_sql );
2193
2194 $cats = [];
2195 if ( ! is_array( $results ) && ! count( $results ) ) {
2196 return $cats;
2197 }
2198 foreach ( $results as $row ) {
2199 $category_id = $row->term_id;
2200 $category_title = $row->name;
2201
2202 $cats[] = [
2203 'value' => $category_id,
2204 'label' => $category_title,
2205 ];
2206 }
2207
2208 return $cats;
2209 }
2210
2211 /**
2212 * @param $search_query
2213 *
2214 * @return array
2215 */
2216 public static function get_registered_post_types( $search_query = null ) {
2217 // Get all registered post types
2218 $registered_post_types = get_post_types(
2219 [
2220 'public' => true,
2221 '_builtin' => false,
2222 ],
2223 'objects'
2224 );
2225
2226 unset( $registered_post_types['elementor_library'] );
2227 unset( $registered_post_types['e-landing-page'] );
2228 unset( $registered_post_types['rtsb_builder'] );
2229
2230 $post_types = [];
2231
2232 // Check if a search query is provided
2233 if ( ! empty( $search_query ) ) {
2234 // Filter post types based on the search query
2235 $registered_post_types = array_filter(
2236 $registered_post_types,
2237 function ( $post_type ) use ( $search_query ) {
2238 return stripos( $post_type->labels->singular_name, $search_query ) !== false;
2239 }
2240 );
2241 // Check if 'post' match the search query and include them if they do
2242 if ( stripos( 'post', $search_query ) !== false ) {
2243 $post_types[] = [
2244 'value' => 'post',
2245 'label' => 'Post',
2246 ];
2247 }
2248 } else {
2249 $post_types[] = [
2250 'value' => 'post',
2251 'label' => 'Post',
2252 ];
2253 }
2254
2255 // Convert the filtered post types to an array
2256 foreach ( $registered_post_types as $post_type ) {
2257 $post_types[] = [
2258 'value' => $post_type->name,
2259 'label' => $post_type->labels->singular_name,
2260 ];
2261 }
2262
2263 return $post_types;
2264 }
2265
2266 /**
2267 * Get Post Types.
2268 *
2269 * @param $search_query
2270 *
2271 * @return array
2272 */
2273 public static function get_post_types( $search_query = null, $args = [] ) {
2274
2275 $args = wp_parse_args(
2276 $args,
2277 [
2278 'post_type' => 'any',
2279 'posts_per_page' => 20,
2280 'orderby' => 'ID',
2281 'order' => 'DESC',
2282 ]
2283 );
2284
2285 if ( 'archive' !== $args['post_type'] ) {
2286 if ( $search_query ) {
2287 $args['s'] = $search_query;
2288 }
2289 $posts = [];
2290 $query_results = get_posts( $args );
2291 foreach ( $query_results as $post ) {
2292 $posts[] = [
2293 'value' => $post->ID,
2294 'label' => $post->post_title,
2295 ];
2296 }
2297 if ( $search_query ) {
2298 if ( strpos( '-error 404', $search_query ) ) {
2299 $posts[] = [
2300 'value' => 'error',
2301 'label' => __( '404 Error', 'shopbuilder' ),
2302 ];
2303 }
2304 } else {
2305 $posts[] = [
2306 'value' => 'error',
2307 'label' => __( '404 Error', 'shopbuilder' ),
2308 ];
2309 }
2310 } else {
2311 $posts = self::get_registered_post_types( $search_query );
2312 }
2313
2314 return $posts;
2315 }
2316
2317 /**
2318 * Get all Elementor breakpoints.
2319 *
2320 * @return array
2321 */
2322 public static function get_elementor_breakpoints() {
2323 return ( new \Elementor\Core\Breakpoints\Manager() )->get_breakpoints_config();
2324 }
2325 }
2326