PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 2.1.13
ShopBuilder – WooCommerce Builder For Elementor v2.1.13
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
← All changes | app/Helpers/Fns.php +395 -71 2.1.32.1.13 View file →
@@ -44,9 +44,58 @@
44 44
45 45 return false;
46 46 }
47 47
48 + public static function get_nonce() {
49 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended
50 + return isset( $_REQUEST[ rtsb()->nonceId ] ) ? sanitize_text_field( $_REQUEST[ rtsb()->nonceId ] ) : null;
51 + }
52 +
53 +
48 54 /**
55 + * Set Cookie or Session
56 + *
57 + * @param $name
58 + * @param $value
59 + */
60 + public static function setSession( $name, $value ) {
61 + if ( ! headers_sent() && session_status() == PHP_SESSION_NONE ) {
62 + session_start();
63 + $_SESSION[ $name ] = $value;
64 + // session_write_close();
65 + } else {
66 + $_SESSION[ $name ] = $value;
67 + }
68 + }
69 + /**
70 + * Get Cookie or Session
71 + *
72 + * @param $name
73 + *
74 + * @return bool
75 + */
76 + public static function getSession( $name ) {
77 + if ( ! headers_sent() && session_status() == PHP_SESSION_NONE ) {
78 + session_start();
79 + }
80 + return $_SESSION[ $name ] ?? null;
81 + }
82 + /**
83 + * Remove Session Variable
84 + *
85 + * @param string $name The name of the session variable to remove.
86 + */
87 + public static function removeSession( $name ) {
88 + if ( ! headers_sent() && session_status() == PHP_SESSION_NONE ) {
89 + session_start();
90 + unset( $_SESSION[ $name ] );
91 + // session_write_close();
92 + } else {
93 + unset( $_SESSION[ $name ] );
94 + }
95 + }
96 +
97 + /**
49 98 * @param $plugin_slug
50 99 *
51 100 * @return bool
52 101 */
@@ -120,14 +169,15 @@
120 169
121 170 /**
122 171 * @param string $template_name Template name.
123 172 * @param string $template_path Template path. (default: '').
124 - * @param string $plugin_path Plugin path. (default: ''). fallback file from plugin
173 + * @param string $plugin_path Plugin path. (default: ''). fallback file from plugin.
125 174 *
126 175 * @return mixed|void
127 176 */
128 177 public static function locate_template( $template_name, $template_path = '', $plugin_path = '' ) {
129 - $template_name = $template_name . '.php';
178 + $template_name = self::sanitize_file_name( $template_name ) . '.php';
179 +
130 180 if ( ! $template_path ) {
131 181 $template_path = rtsb()->get_template_path();
132 182 }
133 183 if ( ! $plugin_path ) {
@@ -170,8 +220,19 @@
170 220 return apply_filters( 'rtsb/core/locate_template', $located, $template_name );
171 221 }
172 222
173 223 /**
224 + * Remove any character that is not alphanumeric, /, _, or -.
225 + *
226 + * @param string $name Name to sanitize.
227 + *
228 + * @return array|string|string[]|null
229 + */
230 + private static function sanitize_file_name( $name ) {
231 + return preg_replace( '/[^a-zA-Z0-9\/_\-]/', '', $name );
232 + }
233 +
234 + /**
174 235 * Template Content
175 236 *
176 237 * @param string $template_name Template name.
177 238 * @param array $args Arguments. (default: array).
@@ -319,8 +380,9 @@
319 380 $cache_key = 'rtsb_prepared_product_id';
320 381 $_post_id = wp_cache_get( $cache_key );
321 382
322 383 if ( false === $_post_id || 'publish' !== get_post_status( $_post_id ) ) {
384 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
323 385 $_post_id = $wpdb->get_var(
324 386 $wpdb->prepare( "SELECT MAX(ID) FROM {$wpdb->prefix}posts WHERE post_type = %s AND post_status IN('publish', 'draft')", 'product' )
325 387 );
326 388 wp_cache_set( $cache_key, $_post_id, '', 12 * HOUR_IN_SECONDS );
@@ -337,9 +399,9 @@
337 399 public static function get_product() {
338 400 global $product;
339 401
340 402 if ( is_singular( 'product' ) && $product instanceof WC_Product ) {
341 - do_action( 'rtsb_before_product_template_render' );
403 + // do_action( 'rtsb_before_product_template_render' );.
342 404 return $product;
343 405 }
344 406 $cache_key = 'prepared_product_for_preview';
345 407 if ( isset( self::$cache[ $cache_key ] ) ) {
@@ -344,9 +406,8 @@
344 406 $cache_key = 'prepared_product_for_preview';
345 407 if ( isset( self::$cache[ $cache_key ] ) ) {
346 408 return self::$cache[ $cache_key ];
347 409 }
348 -
349 410 $product = wc_get_product( self::get_prepared_product_id() );
350 411 self::$cache[ $cache_key ] = $product;
351 412 do_action( 'rtsb_before_product_template_render' );
352 413 return $product;
@@ -362,9 +423,9 @@
362 423 * @return void
363 424 */
364 425 public static function doing_it_wrong( $function, $message, $version ) {
365 426 $message .= ' Backtrace: ' . wp_debug_backtrace_summary();
366 - _doing_it_wrong( $function, $message, $version );
427 + _doing_it_wrong( esc_html( $function ), wp_kses_post( $message ), esc_html( $version ) );
367 428 }
368 429
369 430 /**
370 431 * @return array
@@ -495,13 +556,14 @@
495 556 }
496 557
497 558 if ( strlen( $page_content ) > 0 ) {
498 559 // Search for an existing page with the specified page content (typically a shortcode).
499 - $shortcode = str_replace( [ '<!-- wp:shortcode -->', '<!-- /wp:shortcode -->' ], '', $page_content );
560 + $shortcode = str_replace( [ '<!-- wp:shortcode -->', '<!-- /wp:shortcode -->' ], '', $page_content );
561 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
500 562 $valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_content LIKE %s LIMIT 1;", "%{$shortcode}%" ) );
501 563 } else {
502 564 // Search for an existing page with the specified page slug.
503 - $valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_name = %s LIMIT 1;", $slug ) );
565 + $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
504 566 }
505 567
506 568 $valid_page_found = apply_filters( 'rtsb/core/create_page_id', $valid_page_found, $slug, $page_content, $options );
507 569
@@ -523,12 +585,12 @@
523 585
524 586 // Search for a matching valid trashed page.
525 587 if ( strlen( $page_content ) > 0 ) {
526 588 // Search for an existing page with the specified page content (typically a shortcode).
527 - $trashed_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status = 'trash' AND post_content LIKE %s LIMIT 1;", "%{$page_content}%" ) );
589 + $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
528 590 } else {
529 591 // Search for an existing page with the specified page slug.
530 - $trashed_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status = 'trash' AND post_name = %s LIMIT 1;", $slug ) );
592 + $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
531 593 }
532 594
533 595 if ( $trashed_page_found ) {
534 596 $page_id = $trashed_page_found;
@@ -1030,9 +1092,14 @@
1030 1092 if ( isset( self::$cache[ $cache_key ] ) ) {
1031 1093 return self::$cache[ $cache_key ];
1032 1094 }
1033 1095
1034 - $termList = get_terms( [ $taxonomy ], [ 'hide_empty' => 0 ] );
1096 + $termList = get_terms(
1097 + [
1098 + 'taxonomy' => $taxonomy,
1099 + 'hide_empty' => false,
1100 + ]
1101 + );
1035 1102
1036 1103 if ( is_array( $termList ) && ! empty( $termList ) && empty( $termList['errors'] ) ) {
1037 1104 if ( $placeholder ) {
1038 1105 $terms = [
@@ -1061,9 +1128,9 @@
1061 1128
1062 1129 if ( $attributes ) {
1063 1130 foreach ( $attributes as $tax ) {
1064 1131 if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) ) {
1065 - $termList[ $tax->attribute_name ] = get_terms( wc_attribute_taxonomy_name( $tax->attribute_name ), 'orderby=name&hide_empty=0' );
1132 + $termList[ $tax->attribute_name ] = get_terms( wc_attribute_taxonomy_name( $tax->attribute_name ) );
1066 1133 }
1067 1134 }
1068 1135 }
1069 1136
@@ -1258,8 +1325,23 @@
1258 1325
1259 1326 self::print_html( $html, true );
1260 1327 }
1261 1328
1329 + public static function get_product_simple_rating_html() {
1330 + global $product;
1331 + $html = null;
1332 + $rating_count = $product->get_rating_count();
1333 + $average_rating = $product->get_average_rating();
1334 + $html .= '<div class="product-rating">';
1335 + $html .= wc_get_rating_html( $average_rating, $rating_count );
1336 + $html .= ! empty( $html ) ? '<span class="rtsb-count">(' . $average_rating . ')</span>' : '';
1337 + $html .= '</div>';
1338 +
1339 + self::print_html( $html, true );
1340 + }
1341 +
1342 +
1343 +
1262 1344 /**
1263 1345 * Text truncation.
1264 1346 *
1265 1347 * @param string $text_to_truncate Text.
@@ -1302,8 +1384,14 @@
1302 1384 *
1303 1385 * @return void
1304 1386 */
1305 1387 public static function get_badge_html( $text, $class = 'fill' ) {
1388 + if ( self::is_module_active( 'product_badges' ) && 'rtsb_yes' === $text ) {
1389 + do_action( 'rtsb/modules/product_badges/frontend/display' );
1390 +
1391 + return;
1392 + }
1393 +
1306 1394 if ( empty( $text ) ) {
1307 1395 return;
1308 1396 }
1309 1397 ob_start();
@@ -1310,10 +1398,9 @@
1310 1398 ?>
1311 1399
1312 1400 <ul class="rtsb-promotion-list">
1313 1401 <li class="rtsb-promotion-list-item">
1314 - <span
1315 - class="rtsb-tag-<?php echo ! empty( $class ) ? esc_attr( $class ) : ''; ?>"><?php echo esc_html( $text ); ?></span>
1402 + <span class="rtsb-tag-<?php echo ! empty( $class ) ? esc_attr( $class ) : ''; ?>"><?php echo esc_html( $text ); ?></span>
1316 1403 </li>
1317 1404 </ul>
1318 1405
1319 1406 <?php
@@ -1691,8 +1778,12 @@
1691 1778 if ( ! $product instanceof WC_Product ) {
1692 1779 return '';
1693 1780 }
1694 1781
1782 + if ( ! $product->is_on_sale() ) {
1783 + return '';
1784 + }
1785 +
1695 1786 $percentage = null;
1696 1787 $max_percentage = '';
1697 1788
1698 1789 if ( $product->is_type( 'simple' ) ) {
@@ -1733,10 +1824,10 @@
1733 1824 *
1734 1825 * @return string
1735 1826 */
1736 1827 public static function custom_pagination( $pages = '', $range = 4, $ajax = false ) {
1737 - $html = null;
1738 - $showitems = ( $range * 2 ) + 1;
1828 + $html = null;
1829 + $visible_range = apply_filters( 'rtsb/elements/pagination/visible_range', ( $range * 2 ) + 1 );
1739 1830
1740 1831 global $paged;
1741 1832
1742 1833 if ( is_front_page() ) {
@@ -1764,8 +1855,9 @@
1764 1855
1765 1856 if ( $ajax ) {
1766 1857 $ajaxClass = ' rtsb-pagination-ajax';
1767 1858 $dataAttr = "data-paged='1'";
1859 + $dataAttr .= ' data-visible-range="' . esc_attr( $visible_range ) . '"';
1768 1860 }
1769 1861
1770 1862 if ( 1 !== $pages ) {
1771 1863 $html .= '<div class="rtsb-pagination' . $ajaxClass . '" ' . $dataAttr . '>';
@@ -1770,29 +1862,29 @@
1770 1862 if ( 1 !== $pages ) {
1771 1863 $html .= '<div class="rtsb-pagination' . $ajaxClass . '" ' . $dataAttr . '>';
1772 1864 $html .= '<ul class="pagination-list">';
1773 1865
1774 - if ( $paged > 2 && $paged > $range + 1 && $showitems < $pages ) {
1866 + if ( $paged > 2 && $paged > $visible_range + 1 && $visible_range < $pages ) {
1775 1867 $html .= "<li><a data-paged='1' href='" . get_pagenum_link( 1 ) . "' aria-label='First'>&laquo;</a></li>";
1776 1868 }
1777 1869
1778 - if ( $paged > 1 && $showitems < $pages ) {
1870 + if ( $paged > 1 && $visible_range < $pages ) {
1779 1871 $p = $paged - 1;
1780 1872 $html .= "<li><a data-paged='{$p}' href='" . get_pagenum_link( $p ) . "' aria-label='Previous'>&lsaquo;</a></li>";
1781 1873 }
1782 1874
1783 1875 for ( $i = 1; $i <= $pages; $i++ ) {
1784 - if ( 1 != $pages && ( ! ( $i >= $paged + $range + 1 || $i <= $paged - $range - 1 ) || $pages <= $showitems ) ) {
1876 + if ( 1 != $pages && ( ! ( $i >= $paged + $visible_range + 1 || $i <= $paged - $visible_range - 1 ) || $pages <= $visible_range ) ) {
1785 1877 $html .= ( $paged == $i ) ? '<li class="active"><span>' . $i . '</span></li>' : "<li><a data-paged='{$i}' href='" . get_pagenum_link( $i ) . "'>" . $i . '</a></li>';
1786 1878 }
1787 1879 }
1788 1880
1789 - if ( $paged < $pages && $showitems < $pages ) {
1881 + if ( $paged < $pages && $visible_range < $pages ) {
1790 1882 $p = $paged + 1;
1791 1883 $html .= "<li><a data-paged='{$p}' href=\"" . get_pagenum_link( $paged + 1 ) . "\" aria-label='Next'>&rsaquo;</a></li>";
1792 1884 }
1793 1885
1794 - if ( $paged < $pages - 1 && $paged + $range - 1 < $pages && $showitems < $pages ) {
1886 + if ( $paged < $pages - 1 && $paged + $range - 1 < $pages && $visible_range < $pages ) {
1795 1887 $html .= "<li><a data-paged='{$pages}' href='" . get_pagenum_link( $pages ) . "' aria-label='Last'>&raquo;</a></li>";
1796 1888 }
1797 1889
1798 1890 $html .= '</ul>';
@@ -2150,9 +2242,8 @@
2150 2242 return true;
2151 2243 }
2152 2244 }
2153 2245
2154 -
2155 2246 /***
2156 2247 * Save Settings data
2157 2248 *
2158 2249 * @param $section_id
@@ -2164,10 +2255,9 @@
2164 2255 public static function set_options( $section_id = '', $block_id = '', $rawOptions = [] ) {
2165 2256 $section_id = ! empty( $section_id ) ? sanitize_text_field( wp_unslash( $section_id ) ) : '';
2166 2257 $block_id = ! empty( $block_id ) ? sanitize_text_field( wp_unslash( $block_id ) ) : '';
2167 2258 $rawOptions = ! empty( $rawOptions ) ? $rawOptions : [];
2168 -
2169 - $results = [
2259 + $results = [
2170 2260 'status' => true,
2171 2261 'message' => '',
2172 2262 ];
2173 2263 if ( ! $section_id || ! $block_id ) {
@@ -2183,9 +2273,9 @@
2183 2273
2184 2274 return $results;
2185 2275 }
2186 2276
2187 - $options = DataModel::source()->get_option( $section_id, [] );
2277 + $options = DataModel::source()->get_option( $section_id, [], false );
2188 2278 $changed = false;
2189 2279 $fields = [];
2190 2280 if ( isset( $sections[ $section_id ]['list'][ $block_id ]['fields'] ) && ! empty( $sections[ $section_id ]['list'][ $block_id ]['fields'] ) ) {
2191 2281 $fields = $sections[ $section_id ]['list'][ $block_id ]['fields'];
@@ -2220,10 +2310,16 @@
2220 2310 } else {
2221 2311 $value = [];
2222 2312 }
2223 2313 } else {
2224 - if ( ! empty( $field['sanitize_fn'] ) && is_callable( $field['sanitize_fn'] ) ) {
2225 - $value = $field['sanitize_fn']( $raw_value );
2314 + if ( ! empty( $field['sanitize_fn'] ) ) {
2315 + if ( is_callable( $field['sanitize_fn'] ) ) {
2316 + $value = $field['sanitize_fn']( $raw_value );
2317 + } elseif ( 'pass_all' === $field['sanitize_fn'] ) {
2318 + $value = $raw_value;
2319 + } else {
2320 + $value = $field['sanitize_fn']( $raw_value );
2321 + }
2226 2322 } else {
2227 2323 $value = sanitize_text_field( $raw_value );
2228 2324 }
2229 2325 }
@@ -2269,9 +2365,8 @@
2269 2365 * }
2270 2366 * return;
2271 2367 * }
2272 2368 */
2273 -
2274 2369 public static function count_products_by_taxonomies( $terms, $taxonomy = 'product_cat' ) {
2275 2370 if ( empty( $terms ) || ! is_array( $terms ) ) {
2276 2371 return;
2277 2372 }
@@ -2307,9 +2402,12 @@
2307 2402 if ( 'page' === get_post_type() ) {
2308 2403 return false;
2309 2404 }
2310 2405
2311 - $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page );
2406 + $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page );
2407 + if ( ! $id ) {
2408 + return false;
2409 + }
2312 2410 $cache_key = 'product_filters_has_ajax_' . $id;
2313 2411 if ( isset( self::$cache[ $cache_key ] ) ) {
2314 2412 return self::$cache[ $cache_key ];
2315 2413 }
@@ -2318,8 +2416,9 @@
2318 2416
2319 2417 foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) {
2320 2418 $ajax[] = isset( $data['settings']['ajax_mode'] ) ? false : true;
2321 2419 }
2420 +
2322 2421 self::$cache[ $cache_key ] = ! empty( $ajax[0] );
2323 2422 return ! empty( $ajax[0] );
2324 2423 }
2325 2424
@@ -2337,9 +2436,11 @@
2337 2436
2338 2437 $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page );
2339 2438 $elmap = ElementorDataMap::instance();
2340 2439 $ajax = [];
2341 -
2440 + if ( ! $id ) {
2441 + return false;
2442 + }
2342 2443 foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) {
2343 2444 $ajax[] = ! isset( $data['settings']['active_filter'] );
2344 2445
2345 2446 }
@@ -2372,17 +2473,19 @@
2372 2473 $sql = "SELECT t.term_id, t.name
2373 2474 FROM {$wpdb->terms} t
2374 2475 JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
2375 2476 WHERE tt.taxonomy = 'product_cat'";
2477 +
2376 2478 if ( $search_query ) {
2377 2479 $sql .= ' AND t.name LIKE %s';
2378 - $prepared_sql = $wpdb->prepare( $sql, '%' . $wpdb->esc_like( $search_query ) . '%' ); // Escaping and wildcard
2480 + $prepared_sql = $wpdb->prepare( $sql, '%' . $wpdb->esc_like( $search_query ) . '%' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2379 2481 } else {
2380 - $prepared_sql = $sql; // No need for placeholders
2482 + $prepared_sql = $sql; // No need for placeholders.
2381 2483 }
2382 - $results = $wpdb->get_results( $prepared_sql );
2383 - // Cache the results in the object cache for future use
2384 - wp_cache_set( $cache_key, $results ); // Adjust the expiration time as needed
2484 +
2485 + $results = $wpdb->get_results( $prepared_sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared
2486 + // Cache the results in the object cache for future use.
2487 + wp_cache_set( $cache_key, $results ); // Adjust the expiration time as needed.
2385 2488 }
2386 2489
2387 2490 $cats = [];
2388 2491 if ( ! is_array( $results ) && ! count( $results ) ) {
@@ -2397,20 +2500,20 @@
2397 2500 'label' => $category_title,
2398 2501 ];
2399 2502 }
2400 2503
2401 - // Cache the results in a static variable for the next call
2504 + // Cache the results in a static variable for the next call.
2402 2505 self::$cache[ $cache_key ] = $cats;
2403 2506 return $cats;
2404 2507 }
2405 2508
2406 2509 /**
2407 - * @param $search_query
2510 + * @param string $search_query Search query.
2408 2511 *
2409 2512 * @return array
2410 2513 */
2411 2514 public static function get_registered_post_types( $search_query = null ) {
2412 - // Get all registered post types
2515 + // Get all registered post types.
2413 2516 $registered_post_types = get_post_types(
2414 2517 [
2415 2518 'public' => true,
2416 2519 '_builtin' => false,
@@ -2423,11 +2526,11 @@
2423 2526 unset( $registered_post_types['rtsb_builder'] );
2424 2527
2425 2528 $post_types = [];
2426 2529
2427 - // Check if a search query is provided
2530 + // Check if a search query is provided.
2428 2531 if ( ! empty( $search_query ) ) {
2429 - // Filter post types based on the search query
2532 + // Filter post types based on the search query.
2430 2533 $registered_post_types = array_filter(
2431 2534 $registered_post_types,
2432 2535 function ( $post_type ) use ( $search_query ) {
2433 2536 return stripos( $post_type->labels->singular_name, $search_query ) !== false;
@@ -2432,9 +2535,9 @@
2432 2535 function ( $post_type ) use ( $search_query ) {
2433 2536 return stripos( $post_type->labels->singular_name, $search_query ) !== false;
2434 2537 }
2435 2538 );
2436 - // Check if 'post' match the search query and include them if they do
2539 + // Check if 'post' match the search query and include them if they do.
2437 2540 if ( stripos( 'post', $search_query ) !== false ) {
2438 2541 $post_types[] = [
2439 2542 'value' => 'post',
2440 2543 'label' => 'Post',
@@ -2446,9 +2549,9 @@
2446 2549 'label' => 'Post',
2447 2550 ];
2448 2551 }
2449 2552
2450 - // Convert the filtered post types to an array
2553 + // Convert the filtered post types to an array.
2451 2554 foreach ( $registered_post_types as $post_type ) {
2452 2555 $post_types[] = [
2453 2556 'value' => $post_type->name,
2454 2557 'label' => $post_type->labels->singular_name,
@@ -2460,9 +2563,9 @@
2460 2563
2461 2564 /**
2462 2565 * Get Post Types.
2463 2566 *
2464 - * @param $search_query
2567 + * @param string $search_query Search query.
2465 2568 *
2466 2569 * @return array
2467 2570 */
2468 2571 public static function get_post_types( $search_query = null, $args = [] ) {
@@ -2473,8 +2576,9 @@
2473 2576 'post_type' => 'any',
2474 2577 'posts_per_page' => 20,
2475 2578 'orderby' => 'ID',
2476 2579 'order' => 'DESC',
2580 + // 'suppress_filters' => false, // WPML Support, Remove Others Languages.
2477 2581 ]
2478 2582 );
2479 2583
2480 2584 if ( 'archive' !== $args['post_type'] ) {
@@ -2485,9 +2589,9 @@
2485 2589 $query_results = get_posts( $args );
2486 2590 foreach ( $query_results as $post ) {
2487 2591 $posts[] = [
2488 2592 'value' => $post->ID,
2489 - 'label' => $post->post_title,
2593 + 'label' => $post->post_title . ' (' . $post->ID . ')',
2490 2594 ];
2491 2595 }
2492 2596 if ( $search_query ) {
2493 2597 if ( strpos( '-error 404', $search_query ) ) {
@@ -2549,37 +2653,48 @@
2549 2653 } else {
2550 2654 include $view_file;
2551 2655 }
2552 2656 }
2553 - /**
2554 - * @param int $limit Best-selling Base on product Limit.
2555 - * @param string $return_type id|Object
2556 - *
2557 - * @return int
2558 - */
2559 - public static function best_selling_products( $limit = 10, $return_type = 'id' ) {
2560 - $cache_key = 'best_selling_products' . $return_type . $limit;
2561 - // if ( isset( self::$cache[ $cache_key ] ) ) {
2562 - // return self::$cache[ $cache_key ];
2563 - // }
2564 - // Check if the data is in the cache
2657 +
2658 + /**
2659 + * Best selling product query.
2660 + *
2661 + * @param int $minimum_sale Minimum sale/
2662 + * @param int $limit Total limit.
2663 + *
2664 + * @return array|mixed
2665 + */
2666 + public static function best_selling_products_ids( $minimum_sale = 1, $limit = 10 ) {
2667 + $cache_key = 'rtsb_best_selling_products_' . $minimum_sale . '_' . $limit;
2668 + // Check if the data is in the cache.
2669 + if ( isset( self::$cache[ $cache_key ] ) ) {
2670 + return self::$cache[ $cache_key ];
2671 + }
2565 2672 $cached_data = get_transient( $cache_key );
2566 2673 if ( $cached_data ) {
2674 + self::$cache[ $cache_key ] = $cached_data;
2567 2675 return $cached_data;
2568 2676 }
2569 -
2570 - $args = [
2571 - 'limit' => $limit,
2572 - 'orderby' => 'total_sales',
2573 - ];
2574 - if ( 'id' === strtolower( $return_type ) ) {
2575 - $args['return'] = 'ids';
2576 - }
2577 - $best_selling = wc_get_products( $args );
2578 - // self::$cache[ $cache_key ] = $best_selling;
2579 - // Cache the result for future use
2677 + global $wpdb;
2678 + $sql = $wpdb->prepare(
2679 + "
2680 + SELECT ID
2681 + FROM {$wpdb->posts} AS p
2682 + LEFT JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id
2683 + WHERE p.post_type = 'product'
2684 + AND p.post_status = 'publish'
2685 + AND pm.meta_key = 'total_sales'
2686 + AND pm.meta_value >= %d
2687 + ORDER BY pm.meta_value + 0 DESC
2688 + LIMIT %d
2689 + ",
2690 + $minimum_sale,
2691 + $limit
2692 + );
2693 + $best_selling = $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
2694 + // Cache the result for future use.
2580 2695 set_transient( $cache_key, $best_selling, DAY_IN_SECONDS );
2581 -
2696 + self::$cache[ $cache_key ] = $best_selling;
2582 2697 return $best_selling;
2583 2698 }
2584 2699
2585 2700 /**
@@ -2603,19 +2718,228 @@
2603 2718 if ( isset( self::$cache[ $cache_key ] ) ) {
2604 2719 return self::$cache[ $cache_key ];
2605 2720 }
2606 2721
2607 - // Get the product publish date
2722 + // Get the product publish date.
2608 2723 $publish_timestamp = strtotime( $product->get_date_created()->date_i18n( 'Y-m-d H:i:s' ) );
2609 2724
2610 - // Calculate the difference in days
2725 + // Calculate the difference in days.
2611 2726 $days_difference = abs( time() - $publish_timestamp ) / ( 60 * 60 * 24 );
2612 2727
2613 - // Check if the product is considered new
2728 + // Check if the product is considered new.
2614 2729 $is_new = $days_difference <= $days_threshold;
2615 2730
2616 - // Cache the result for a day
2731 + // Cache the result for a day.
2617 2732 self::$cache[ $cache_key ] = $is_new;
2618 2733
2619 2734 return $is_new;
2735 + }
2736 +
2737 + /**
2738 + * Checks if a feature is disabled for guest users based on the provided option.
2739 + *
2740 + * @param string $option The option to retrieve from the item.
2741 + * @param mixed $default The default value if the option is not found.
2742 + *
2743 + * @return bool
2744 + */
2745 + public static function is_guest_feature_disabled( $option, $default ) {
2746 + $disabled = self::get_option( 'general', 'guest_user', $option, $default );
2747 +
2748 + return ! is_user_logged_in() && $disabled;
2749 + }
2750 +
2751 + /**
2752 + * Checks if a feature is disabled for guest users based on the provided option.
2753 + *
2754 + * @param string $option The option to retrieve from the item.
2755 + * @param mixed $default The default value if the option is not found.
2756 + *
2757 + * @return bool
2758 + */
2759 + public static function woocommerce_output_all_notices() {
2760 + if ( function_exists( 'wc_print_notices' ) ) :
2761 + echo '<div class="rtsb-notice">';
2762 + woocommerce_output_all_notices();
2763 + echo '</div>';
2764 + endif;
2765 + }
2766 +
2767 + /**
2768 + * @param object $product Product.
2769 + * @return bool
2770 + */
2771 + public static function is_visible_qty_input( $product = null ) {
2772 + $is_visible_qty = true;
2773 + if ( $product instanceof \WC_Product ) {
2774 + if ( $product->is_sold_individually() ) {
2775 + $is_visible_qty = false;
2776 + } elseif ( $product->managing_stock() ) {
2777 + if ( in_array( $product->get_backorders(), [ 'notify' , 'yes' ], true ) ) {
2778 + $is_visible_qty = true;
2779 + } elseif ( $product->get_stock_quantity() < 2 ) {
2780 + $is_visible_qty = false;
2781 + }
2782 + }
2783 + }
2784 + return $is_visible_qty;
2785 + }
2786 +
2787 + /**
2788 + * @param int $object_id Object id.
2789 + * @param string $element_type element type.
2790 + * @param string|null $current_lang null for current language, default for default languages.
2791 + * @return false|mixed|null
2792 + */
2793 + public static function wpml_object_id( $object_id, $element_type, $current_lang = 'default' ) {
2794 + if ( ! defined( 'ICL_SITEPRESS_VERSION' ) ) {
2795 + return $object_id;
2796 + }
2797 + if ( ! $object_id || ! $element_type ) {
2798 + return $object_id;
2799 + }
2800 + if ( 'default' === $current_lang ) {
2801 + $lang = apply_filters( 'wpml_default_language', null );
2802 + } else {
2803 + $lang = null;
2804 + }
2805 + return apply_filters( 'wpml_object_id', $object_id, $element_type, false, $lang );
2806 + }
2807 +
2808 + /**
2809 + * @return string
2810 + */
2811 + public static function wpml_current_language() {
2812 + $current = apply_filters( 'wpml_current_language', null );
2813 + $default = apply_filters( 'wpml_default_language', null );
2814 + return $default !== $current ? $current : null;
2815 + }
2816 +
2817 + /**
2818 + * Custom icons.
2819 + *
2820 + * @return string[]
2821 + */
2822 + public static function get_custom_icon_names() {
2823 + return [
2824 + 'heart-empty',
2825 + 'heart',
2826 + 'eye',
2827 + 'exchange',
2828 + 'plus',
2829 + 'minus',
2830 + 'avatar',
2831 + 'pay',
2832 + 'share',
2833 + 'clock',
2834 + 'check-alt',
2835 + 'check',
2836 + 'delete',
2837 + 'marker',
2838 + 'list',
2839 + 'list-2',
2840 + 'power',
2841 + 'cart',
2842 + 'cart-2',
2843 + 'cart-3',
2844 + 'downloads',
2845 + 'zoom',
2846 + 'user-edit',
2847 + 'grid',
2848 + 'filter',
2849 + 'billing',
2850 + 'login',
2851 + 'payment',
2852 + 'search',
2853 + 'edit',
2854 + 'coupon',
2855 + 'arrows-cw',
2856 + 'trash-empty',
2857 + ];
2858 + }
2859 +
2860 + /**
2861 + * Flushes rewrite rules.
2862 + *
2863 + * @return void
2864 + */
2865 + public static function maybe_flush_rewrite_rules() {
2866 + add_action( 'wp_loaded', [ __CLASS__, 'flush_rewrite_rules' ] );
2867 + add_action( 'shutdown', [ __CLASS__, 'flush_rewrite_rules_once_more' ] );
2868 + }
2869 +
2870 + /**
2871 + * Flushes rewrite rules if needed.
2872 + *
2873 + * @return void
2874 + */
2875 + public static function flush_rewrite_rules() {
2876 + if ( get_option( 'rtsb_permalinks_need_flush' ) === 'yes' ) {
2877 + flush_rewrite_rules();
2878 + }
2879 +
2880 + if ( get_option( 'rtsb_permalinks_flushed' ) === 'yes' ) {
2881 + flush_rewrite_rules();
2882 + delete_option( 'rtsb_permalinks_flushed' );
2883 + }
2884 + }
2885 +
2886 + /**
2887 + * Flushes rewrite rules if needed for second time.
2888 + *
2889 + * @return void
2890 + */
2891 + public static function flush_rewrite_rules_once_more() {
2892 + if ( get_option( 'rtsb_permalinks_need_flush' ) === 'yes' ) {
2893 + flush_rewrite_rules();
2894 + update_option( 'rtsb_permalinks_flushed', 'yes' );
2895 + delete_option( 'rtsb_permalinks_need_flush' );
2896 + }
2897 + }
2898 +
2899 + /**
2900 + * Social Share Platforms.
2901 + *
2902 + * @return mixed|null
2903 + */
2904 + public static function set_repeater_options( $section_id, $block_id, $option_key, $compare_key, $compare_value, $values ) {
2905 + // $options = self::get_options( $section_id, $block_id );
2906 + $modules = DataModel::source()->get_option( $section_id, [], false );
2907 + if ( empty( $modules[ $block_id ] ) ) {
2908 + return;
2909 + }
2910 + $options = $modules[ $block_id ];
2911 + if ( empty( $options[ $option_key ] ) ) {
2912 + return;
2913 + }
2914 + $repeater_options = json_decode( $options[ $option_key ], true );
2915 + // Check if options are not empty and are in array format.
2916 + if ( ! is_array( $repeater_options ) ) {
2917 + return;
2918 + }
2919 + // Use array_column to get an array of values from $compare_key.
2920 + $column_values = array_column( $repeater_options, $compare_key );
2921 + // Use array_search to find the index of the $compare_value.
2922 + $index = array_search( $compare_value, $column_values, true );
2923 + if ( false === $index ) {
2924 + return;
2925 + }
2926 + $repeater_options[ $index ] = wp_parse_args( $values, $repeater_options[ $index ] );
2927 + $options[ $option_key ] = wp_json_encode( $repeater_options );
2928 + self::set_options( $section_id, $block_id, $options );
2929 + }
2930 +
2931 +
2932 + /**
2933 + * @param array $ids products id.
2934 + * @return array
2935 + */
2936 + public static function get_available_products_by_ids( $ids = [] ) {
2937 + $ids = array_filter(
2938 + $ids,
2939 + function ( $id ) {
2940 + return 'product' === get_post_type( $id ) && 'publish' === get_post_status( $id );
2941 + }
2942 + );
2943 + return $ids;
2620 2944 }
2621 2945 }