| @@ -44,9 +44,55 @@ | ||
| 44 | 44 | |
| 45 | 45 | return false; |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | + public static function get_nonce() { | |
| 49 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized | |
| 50 | + return isset( $_REQUEST[ rtsb()->nonceId ] ) ? sanitize_text_field( $_REQUEST[ rtsb()->nonceId ] ) : null; | |
| 51 | + } | |
| 52 | + | |
| 48 | 53 | /** |
| 54 | + * Set Cookie or Session | |
| 55 | + * | |
| 56 | + * @param $name | |
| 57 | + * @param $value | |
| 58 | + */ | |
| 59 | + public static function setSession( $name, $value ) { | |
| 60 | + if ( ! headers_sent() && session_status() == PHP_SESSION_NONE ) { | |
| 61 | + session_start(); | |
| 62 | + $_SESSION[ $name ] = $value; | |
| 63 | + } else { | |
| 64 | + $_SESSION[ $name ] = $value; | |
| 65 | + } | |
| 66 | + } | |
| 67 | + /** | |
| 68 | + * Get Cookie or Session | |
| 69 | + * | |
| 70 | + * @param $name | |
| 71 | + * | |
| 72 | + * @return bool | |
| 73 | + */ | |
| 74 | + public static function getSession( $name ) { | |
| 75 | + if ( ! headers_sent() && session_status() == PHP_SESSION_NONE ) { | |
| 76 | + session_start(); | |
| 77 | + } | |
| 78 | + return $_SESSION[ $name ] ?? null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized | |
| 79 | + } | |
| 80 | + /** | |
| 81 | + * Remove Session Variable | |
| 82 | + * | |
| 83 | + * @param string $name The name of the session variable to remove. | |
| 84 | + */ | |
| 85 | + public static function removeSession( $name ) { | |
| 86 | + if ( ! headers_sent() && session_status() == PHP_SESSION_NONE ) { | |
| 87 | + session_start(); | |
| 88 | + unset( $_SESSION[ $name ] ); | |
| 89 | + } else { | |
| 90 | + unset( $_SESSION[ $name ] ); | |
| 91 | + } | |
| 92 | + } | |
| 93 | + | |
| 94 | + /** | |
| 49 | 95 | * @param $plugin_slug |
| 50 | 96 | * |
| 51 | 97 | * @return bool |
| 52 | 98 | */ |
| @@ -67,9 +113,46 @@ | ||
| 67 | 113 | } |
| 68 | 114 | |
| 69 | 115 | return false; |
| 70 | 116 | } |
| 117 | + /** | |
| 118 | + * Get all user roles. | |
| 119 | + * | |
| 120 | + * @return array|false|mixed | |
| 121 | + */ | |
| 122 | + public static function get_current_user_roles() { | |
| 123 | + $current_user = wp_get_current_user(); | |
| 124 | + return $current_user->roles; | |
| 125 | + } | |
| 126 | + /** | |
| 127 | + * Get all user roles. | |
| 128 | + * | |
| 129 | + * @return array|false|mixed | |
| 130 | + */ | |
| 131 | + public static function get_all_user_roles() { | |
| 132 | + $cache_key = 'rtsb_get_user_roles'; | |
| 133 | + $roles = wp_cache_get( $cache_key, 'shopbuilder' ); | |
| 71 | 134 | |
| 135 | + if ( empty( $roles ) ) { | |
| 136 | + if ( ! function_exists( 'get_editable_roles' ) ) { | |
| 137 | + require_once ABSPATH . 'wp-admin/includes/user.php'; | |
| 138 | + } | |
| 139 | + | |
| 140 | + $user_roles = \get_editable_roles(); | |
| 141 | + $roles = []; | |
| 142 | + | |
| 143 | + foreach ( $user_roles as $key => $role ) { | |
| 144 | + if ( empty( $role['capabilities'] ) ) { | |
| 145 | + continue; | |
| 146 | + } | |
| 147 | + $roles[ $key ] = $role['name']; | |
| 148 | + } | |
| 149 | + } | |
| 150 | + wp_cache_set( $cache_key, $roles, 'shopbuilder' ); | |
| 151 | + Cache::set_data_cache_key( $cache_key ); | |
| 152 | + return $roles; | |
| 153 | + } | |
| 154 | + | |
| 72 | 155 | /** |
| 73 | 156 | * @param $data |
| 74 | 157 | * |
| 75 | 158 | * @return mixed|string |
| @@ -120,14 +203,15 @@ | ||
| 120 | 203 | |
| 121 | 204 | /** |
| 122 | 205 | * @param string $template_name Template name. |
| 123 | 206 | * @param string $template_path Template path. (default: ''). |
| 124 | - * @param string $plugin_path Plugin path. (default: ''). fallback file from plugin | |
| 207 | + * @param string $plugin_path Plugin path. (default: ''). fallback file from plugin. | |
| 125 | 208 | * |
| 126 | 209 | * @return mixed|void |
| 127 | 210 | */ |
| 128 | 211 | public static function locate_template( $template_name, $template_path = '', $plugin_path = '' ) { |
| 129 | - $template_name = $template_name . '.php'; | |
| 212 | + $template_name = self::sanitize_file_name( $template_name ) . '.php'; | |
| 213 | + | |
| 130 | 214 | if ( ! $template_path ) { |
| 131 | 215 | $template_path = rtsb()->get_template_path(); |
| 132 | 216 | } |
| 133 | 217 | if ( ! $plugin_path ) { |
| @@ -170,8 +254,19 @@ | ||
| 170 | 254 | return apply_filters( 'rtsb/core/locate_template', $located, $template_name ); |
| 171 | 255 | } |
| 172 | 256 | |
| 173 | 257 | /** |
| 258 | + * Remove any character that is not alphanumeric, /, _, or -. | |
| 259 | + * | |
| 260 | + * @param string $name Name to sanitize. | |
| 261 | + * | |
| 262 | + * @return array|string|string[]|null | |
| 263 | + */ | |
| 264 | + private static function sanitize_file_name( $name ) { | |
| 265 | + return preg_replace( '/[^a-zA-Z0-9\/_\-]/', '', $name ); | |
| 266 | + } | |
| 267 | + | |
| 268 | + /** | |
| 174 | 269 | * Template Content |
| 175 | 270 | * |
| 176 | 271 | * @param string $template_name Template name. |
| 177 | 272 | * @param array $args Arguments. (default: array). |
| @@ -181,10 +276,19 @@ | ||
| 181 | 276 | * |
| 182 | 277 | * @return false|string|void |
| 183 | 278 | */ |
| 184 | 279 | public static function load_template( $template_name, array $args = null, $return = false, $template_path = '', $plugin_path = '' ) { |
| 185 | - $located = self::locate_template( $template_name, $template_path, $plugin_path ); | |
| 186 | - | |
| 280 | + $cache_key = sanitize_key( implode( '-', [ 'template', $template_name, $template_path ] ) ); | |
| 281 | + $located = (string) wp_cache_get( $cache_key, 'shopbuilder' ); | |
| 282 | + if ( ! $located ) { | |
| 283 | + $located = self::locate_template( $template_name, $template_path, $plugin_path ); | |
| 284 | + // Don't cache the absolute path so that it can be shared between web servers with different paths. | |
| 285 | + $cache_path = wc_tokenize_path( $located, wc_get_path_define_tokens() ); | |
| 286 | + Cache::set_template_cache( $cache_key, $cache_path ); | |
| 287 | + } else { | |
| 288 | + // Make sure that the absolute path to the template is resolved. | |
| 289 | + $located = wc_untokenize_path( $located, wc_get_path_define_tokens() ); | |
| 290 | + } | |
| 187 | 291 | if ( ! file_exists( $located ) ) { |
| 188 | 292 | // translators: %s template. |
| 189 | 293 | self::doing_it_wrong( __FUNCTION__, sprintf( __( '%s does not exist.', 'shopbuilder' ), '<code>' . $located . '</code>' ), '1.0' ); |
| 190 | 294 | |
| @@ -192,9 +296,9 @@ | ||
| 192 | 296 | } |
| 193 | 297 | |
| 194 | 298 | if ( ! empty( $args ) && is_array( $args ) ) { |
| 195 | 299 | $atts = $args; |
| 196 | - extract( $args ); // @codingStandardsIgnoreLine | |
| 300 | + extract( $args ); // @codingStandardsIgnoreLine | |
| 197 | 301 | } |
| 198 | 302 | |
| 199 | 303 | // Allow 3rd party plugin filter template file from their plugin. |
| 200 | 304 | $located = apply_filters( 'rtsb/core/get_template', $located, $template_name, $args ); |
| @@ -309,9 +413,9 @@ | ||
| 309 | 413 | // Return the Builder Template id. |
| 310 | 414 | |
| 311 | 415 | if ( get_post_type( get_the_ID() ) == BuilderFns::$post_type_tb ) { |
| 312 | 416 | $product_id = get_post_meta( get_the_ID(), BuilderFns::$product_template_meta, true ); |
| 313 | - if ( $product_id ) { | |
| 417 | + if ( $product_id && get_post_status( $product_id ) ) { | |
| 314 | 418 | return $product_id; |
| 315 | 419 | } |
| 316 | 420 | } |
| 317 | 421 | |
| @@ -316,15 +420,16 @@ | ||
| 316 | 420 | } |
| 317 | 421 | |
| 318 | 422 | global $wpdb; |
| 319 | 423 | $cache_key = 'rtsb_prepared_product_id'; |
| 320 | - $_post_id = wp_cache_get( $cache_key ); | |
| 321 | - | |
| 424 | + $_post_id = wp_cache_get( $cache_key, 'shopbuilder' ); | |
| 322 | 425 | if ( false === $_post_id || 'publish' !== get_post_status( $_post_id ) ) { |
| 426 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery | |
| 323 | 427 | $_post_id = $wpdb->get_var( |
| 324 | 428 | $wpdb->prepare( "SELECT MAX(ID) FROM {$wpdb->prefix}posts WHERE post_type = %s AND post_status IN('publish', 'draft')", 'product' ) |
| 325 | 429 | ); |
| 326 | - wp_cache_set( $cache_key, $_post_id, '', 12 * HOUR_IN_SECONDS ); | |
| 430 | + wp_cache_set( $cache_key, $_post_id, 'shopbuilder', 12 * HOUR_IN_SECONDS ); | |
| 431 | + Cache::set_data_cache_key( $cache_key ); | |
| 327 | 432 | } |
| 328 | 433 | |
| 329 | 434 | return $_post_id; |
| 330 | 435 | } |
| @@ -337,9 +442,9 @@ | ||
| 337 | 442 | public static function get_product() { |
| 338 | 443 | global $product; |
| 339 | 444 | |
| 340 | 445 | if ( is_singular( 'product' ) && $product instanceof WC_Product ) { |
| 341 | - do_action( 'rtsb_before_product_template_render' ); | |
| 446 | + // do_action( 'rtsb_before_product_template_render' );. | |
| 342 | 447 | return $product; |
| 343 | 448 | } |
| 344 | 449 | $cache_key = 'prepared_product_for_preview'; |
| 345 | 450 | if ( isset( self::$cache[ $cache_key ] ) ) { |
| @@ -344,9 +449,8 @@ | ||
| 344 | 449 | $cache_key = 'prepared_product_for_preview'; |
| 345 | 450 | if ( isset( self::$cache[ $cache_key ] ) ) { |
| 346 | 451 | return self::$cache[ $cache_key ]; |
| 347 | 452 | } |
| 348 | - | |
| 349 | 453 | $product = wc_get_product( self::get_prepared_product_id() ); |
| 350 | 454 | self::$cache[ $cache_key ] = $product; |
| 351 | 455 | do_action( 'rtsb_before_product_template_render' ); |
| 352 | 456 | return $product; |
| @@ -361,10 +465,11 @@ | ||
| 361 | 465 | * |
| 362 | 466 | * @return void |
| 363 | 467 | */ |
| 364 | 468 | public static function doing_it_wrong( $function, $message, $version ) { |
| 469 | + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_wp_debug_backtrace_summary | |
| 365 | 470 | $message .= ' Backtrace: ' . wp_debug_backtrace_summary(); |
| 366 | - _doing_it_wrong( $function, $message, $version ); | |
| 471 | + _doing_it_wrong( esc_html( $function ), wp_kses_post( $message ), esc_html( $version ) ); | |
| 367 | 472 | } |
| 368 | 473 | |
| 369 | 474 | /** |
| 370 | 475 | * @return array |
| @@ -495,13 +600,14 @@ | ||
| 495 | 600 | } |
| 496 | 601 | |
| 497 | 602 | if ( strlen( $page_content ) > 0 ) { |
| 498 | 603 | // Search for an existing page with the specified page content (typically a shortcode). |
| 499 | - $shortcode = str_replace( [ '<!-- wp:shortcode -->', '<!-- /wp:shortcode -->' ], '', $page_content ); | |
| 604 | + $shortcode = str_replace( [ '<!-- wp:shortcode -->', '<!-- /wp:shortcode -->' ], '', $page_content ); | |
| 605 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 500 | 606 | $valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_content LIKE %s LIMIT 1;", "%{$shortcode}%" ) ); |
| 501 | 607 | } else { |
| 502 | 608 | // 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 ) ); | |
| 609 | + $valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_name = %s LIMIT 1;", $slug ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 504 | 610 | } |
| 505 | 611 | |
| 506 | 612 | $valid_page_found = apply_filters( 'rtsb/core/create_page_id', $valid_page_found, $slug, $page_content, $options ); |
| 507 | 613 | |
| @@ -523,12 +629,12 @@ | ||
| 523 | 629 | |
| 524 | 630 | // Search for a matching valid trashed page. |
| 525 | 631 | if ( strlen( $page_content ) > 0 ) { |
| 526 | 632 | // 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}%" ) ); | |
| 633 | + $trashed_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status = 'trash' AND post_content LIKE %s LIMIT 1;", "%{$page_content}%" ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 528 | 634 | } else { |
| 529 | 635 | // 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 ) ); | |
| 636 | + $trashed_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status = 'trash' AND post_name = %s LIMIT 1;", $slug ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 531 | 637 | } |
| 532 | 638 | |
| 533 | 639 | if ( $trashed_page_found ) { |
| 534 | 640 | $page_id = $trashed_page_found; |
| @@ -899,13 +1005,15 @@ | ||
| 899 | 1005 | return $allowed_html; |
| 900 | 1006 | } |
| 901 | 1007 | |
| 902 | 1008 | /** |
| 903 | - * Safe print a validated HTML tag. | |
| 1009 | + * Safe get a validated HTML tag. | |
| 904 | 1010 | * |
| 905 | - * @param string $tag | |
| 1011 | + * @param string $tag HTML tag. | |
| 1012 | + * | |
| 1013 | + * @return string | |
| 906 | 1014 | */ |
| 907 | - public static function print_validated_html_tag( $tag ) { | |
| 1015 | + public static function get_validated_html_tag( $tag ) { | |
| 908 | 1016 | $allowed_html_wrapper_tags = [ |
| 909 | 1017 | 'a', |
| 910 | 1018 | 'article', |
| 911 | 1019 | 'aside', |
| @@ -925,12 +1033,23 @@ | ||
| 925 | 1033 | 'section', |
| 926 | 1034 | 'span', |
| 927 | 1035 | ]; |
| 928 | 1036 | |
| 929 | - self::print_html( in_array( strtolower( $tag ), $allowed_html_wrapper_tags, true ) ? $tag : 'div' ); | |
| 1037 | + return in_array( strtolower( $tag ), $allowed_html_wrapper_tags, true ) ? $tag : 'div'; | |
| 930 | 1038 | } |
| 931 | 1039 | |
| 932 | 1040 | /** |
| 1041 | + * Safe print a validated HTML tag. | |
| 1042 | + * | |
| 1043 | + * @param string $tag HTML tag. | |
| 1044 | + * | |
| 1045 | + * @return void | |
| 1046 | + */ | |
| 1047 | + public static function print_validated_html_tag( $tag ) { | |
| 1048 | + self::print_html( self::get_validated_html_tag( $tag ) ); | |
| 1049 | + } | |
| 1050 | + | |
| 1051 | + /** | |
| 933 | 1052 | * Insert Some array element |
| 934 | 1053 | * |
| 935 | 1054 | * @param [type] $key The elements will insert nearby this key. |
| 936 | 1055 | * @param [type] $main_array Original array. |
| @@ -1030,9 +1149,14 @@ | ||
| 1030 | 1149 | if ( isset( self::$cache[ $cache_key ] ) ) { |
| 1031 | 1150 | return self::$cache[ $cache_key ]; |
| 1032 | 1151 | } |
| 1033 | 1152 | |
| 1034 | - $termList = get_terms( [ $taxonomy ], [ 'hide_empty' => 0 ] ); | |
| 1153 | + $termList = get_terms( | |
| 1154 | + [ | |
| 1155 | + 'taxonomy' => $taxonomy, | |
| 1156 | + 'hide_empty' => false, | |
| 1157 | + ] | |
| 1158 | + ); | |
| 1035 | 1159 | |
| 1036 | 1160 | if ( is_array( $termList ) && ! empty( $termList ) && empty( $termList['errors'] ) ) { |
| 1037 | 1161 | if ( $placeholder ) { |
| 1038 | 1162 | $terms = [ |
| @@ -1061,9 +1185,9 @@ | ||
| 1061 | 1185 | |
| 1062 | 1186 | if ( $attributes ) { |
| 1063 | 1187 | foreach ( $attributes as $tax ) { |
| 1064 | 1188 | 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' ); | |
| 1189 | + $termList[ $tax->attribute_name ] = get_terms( wc_attribute_taxonomy_name( $tax->attribute_name ) ); | |
| 1066 | 1190 | } |
| 1067 | 1191 | } |
| 1068 | 1192 | } |
| 1069 | 1193 | |
| @@ -1231,9 +1355,9 @@ | ||
| 1231 | 1355 | |
| 1232 | 1356 | if ( $args['show_rating_count'] ) { |
| 1233 | 1357 | $count .= '<div class="rtsb-count">'; |
| 1234 | 1358 | $count .= sprintf( |
| 1235 | - /* translators: %s is the number of reviews */ | |
| 1359 | + /* translators: %s is the number of reviews */ | |
| 1236 | 1360 | _n( '%s Review', '%s Reviews', $rating_count, 'shopbuilder' ), |
| 1237 | 1361 | $rating_count |
| 1238 | 1362 | ); |
| 1239 | 1363 | $count .= '</div>'; |
| @@ -1258,8 +1382,23 @@ | ||
| 1258 | 1382 | |
| 1259 | 1383 | self::print_html( $html, true ); |
| 1260 | 1384 | } |
| 1261 | 1385 | |
| 1386 | + public static function get_product_simple_rating_html() { | |
| 1387 | + global $product; | |
| 1388 | + $html = null; | |
| 1389 | + $rating_count = $product->get_rating_count(); | |
| 1390 | + $average_rating = $product->get_average_rating(); | |
| 1391 | + $html .= '<div class="product-rating">'; | |
| 1392 | + $html .= wc_get_rating_html( $average_rating, $rating_count ); | |
| 1393 | + $html .= ! empty( $html ) ? '<span class="rtsb-count">(' . $average_rating . ')</span>' : ''; | |
| 1394 | + $html .= '</div>'; | |
| 1395 | + | |
| 1396 | + self::print_html( $html, true ); | |
| 1397 | + } | |
| 1398 | + | |
| 1399 | + | |
| 1400 | + | |
| 1262 | 1401 | /** |
| 1263 | 1402 | * Text truncation. |
| 1264 | 1403 | * |
| 1265 | 1404 | * @param string $text_to_truncate Text. |
| @@ -1302,8 +1441,14 @@ | ||
| 1302 | 1441 | * |
| 1303 | 1442 | * @return void |
| 1304 | 1443 | */ |
| 1305 | 1444 | public static function get_badge_html( $text, $class = 'fill' ) { |
| 1445 | + if ( self::is_module_active( 'product_badges' ) && 'rtsb_yes' === $text ) { | |
| 1446 | + do_action( 'rtsb/modules/product_badges/frontend/display' ); | |
| 1447 | + | |
| 1448 | + return; | |
| 1449 | + } | |
| 1450 | + | |
| 1306 | 1451 | if ( empty( $text ) ) { |
| 1307 | 1452 | return; |
| 1308 | 1453 | } |
| 1309 | 1454 | ob_start(); |
| @@ -1310,10 +1455,9 @@ | ||
| 1310 | 1455 | ?> |
| 1311 | 1456 | |
| 1312 | 1457 | <ul class="rtsb-promotion-list"> |
| 1313 | 1458 | <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> | |
| 1459 | + <span class="rtsb-tag-<?php echo ! empty( $class ) ? esc_attr( $class ) : ''; ?>"><?php echo esc_html( $text ); ?></span> | |
| 1316 | 1460 | </li> |
| 1317 | 1461 | </ul> |
| 1318 | 1462 | |
| 1319 | 1463 | <?php |
| @@ -1691,13 +1835,17 @@ | ||
| 1691 | 1835 | if ( ! $product instanceof WC_Product ) { |
| 1692 | 1836 | return ''; |
| 1693 | 1837 | } |
| 1694 | 1838 | |
| 1839 | + if ( ! $product->is_on_sale() ) { | |
| 1840 | + return ''; | |
| 1841 | + } | |
| 1842 | + | |
| 1695 | 1843 | $percentage = null; |
| 1696 | 1844 | $max_percentage = ''; |
| 1697 | 1845 | |
| 1698 | 1846 | if ( $product->is_type( 'simple' ) ) { |
| 1699 | - $max_percentage = ( ( $product->get_regular_price() - $product->get_sale_price() ) / $product->get_regular_price() ) * 100; | |
| 1847 | + $max_percentage = $product->get_sale_price() ? ( ( $product->get_regular_price() - $product->get_sale_price() ) / $product->get_regular_price() ) * 100 : 0; | |
| 1700 | 1848 | } elseif ( $product->is_type( 'variable' ) ) { |
| 1701 | 1849 | $max_percentage = 0; |
| 1702 | 1850 | |
| 1703 | 1851 | foreach ( $product->get_children() as $child_id ) { |
| @@ -1733,10 +1881,10 @@ | ||
| 1733 | 1881 | * |
| 1734 | 1882 | * @return string |
| 1735 | 1883 | */ |
| 1736 | 1884 | public static function custom_pagination( $pages = '', $range = 4, $ajax = false ) { |
| 1737 | - $html = null; | |
| 1738 | - $showitems = ( $range * 2 ) + 1; | |
| 1885 | + $html = null; | |
| 1886 | + $visible_range = apply_filters( 'rtsb/elements/pagination/visible_range', ( $range * 2 ) + 1 ); | |
| 1739 | 1887 | |
| 1740 | 1888 | global $paged; |
| 1741 | 1889 | |
| 1742 | 1890 | if ( is_front_page() ) { |
| @@ -1764,8 +1912,9 @@ | ||
| 1764 | 1912 | |
| 1765 | 1913 | if ( $ajax ) { |
| 1766 | 1914 | $ajaxClass = ' rtsb-pagination-ajax'; |
| 1767 | 1915 | $dataAttr = "data-paged='1'"; |
| 1916 | + $dataAttr .= ' data-visible-range="' . esc_attr( $visible_range ) . '"'; | |
| 1768 | 1917 | } |
| 1769 | 1918 | |
| 1770 | 1919 | if ( 1 !== $pages ) { |
| 1771 | 1920 | $html .= '<div class="rtsb-pagination' . $ajaxClass . '" ' . $dataAttr . '>'; |
| @@ -1770,29 +1919,29 @@ | ||
| 1770 | 1919 | if ( 1 !== $pages ) { |
| 1771 | 1920 | $html .= '<div class="rtsb-pagination' . $ajaxClass . '" ' . $dataAttr . '>'; |
| 1772 | 1921 | $html .= '<ul class="pagination-list">'; |
| 1773 | 1922 | |
| 1774 | - if ( $paged > 2 && $paged > $range + 1 && $showitems < $pages ) { | |
| 1923 | + if ( $paged > 2 && $paged > $visible_range + 1 && $visible_range < $pages ) { | |
| 1775 | 1924 | $html .= "<li><a data-paged='1' href='" . get_pagenum_link( 1 ) . "' aria-label='First'>«</a></li>"; |
| 1776 | 1925 | } |
| 1777 | 1926 | |
| 1778 | - if ( $paged > 1 && $showitems < $pages ) { | |
| 1927 | + if ( $paged > 1 && $visible_range < $pages ) { | |
| 1779 | 1928 | $p = $paged - 1; |
| 1780 | 1929 | $html .= "<li><a data-paged='{$p}' href='" . get_pagenum_link( $p ) . "' aria-label='Previous'>‹</a></li>"; |
| 1781 | 1930 | } |
| 1782 | 1931 | |
| 1783 | 1932 | for ( $i = 1; $i <= $pages; $i++ ) { |
| 1784 | - if ( 1 != $pages && ( ! ( $i >= $paged + $range + 1 || $i <= $paged - $range - 1 ) || $pages <= $showitems ) ) { | |
| 1933 | + if ( 1 != $pages && ( ! ( $i >= $paged + $visible_range + 1 || $i <= $paged - $visible_range - 1 ) || $pages <= $visible_range ) ) { | |
| 1785 | 1934 | $html .= ( $paged == $i ) ? '<li class="active"><span>' . $i . '</span></li>' : "<li><a data-paged='{$i}' href='" . get_pagenum_link( $i ) . "'>" . $i . '</a></li>'; |
| 1786 | 1935 | } |
| 1787 | 1936 | } |
| 1788 | 1937 | |
| 1789 | - if ( $paged < $pages && $showitems < $pages ) { | |
| 1938 | + if ( $paged < $pages && $visible_range < $pages ) { | |
| 1790 | 1939 | $p = $paged + 1; |
| 1791 | 1940 | $html .= "<li><a data-paged='{$p}' href=\"" . get_pagenum_link( $paged + 1 ) . "\" aria-label='Next'>›</a></li>"; |
| 1792 | 1941 | } |
| 1793 | 1942 | |
| 1794 | - if ( $paged < $pages - 1 && $paged + $range - 1 < $pages && $showitems < $pages ) { | |
| 1943 | + if ( $paged < $pages - 1 && $paged + $range - 1 < $pages && $visible_range < $pages ) { | |
| 1795 | 1944 | $html .= "<li><a data-paged='{$pages}' href='" . get_pagenum_link( $pages ) . "' aria-label='Last'>»</a></li>"; |
| 1796 | 1945 | } |
| 1797 | 1946 | |
| 1798 | 1947 | $html .= '</ul>'; |
| @@ -2051,9 +2200,9 @@ | ||
| 2051 | 2200 | $link['social_action'] = 'Share'; |
| 2052 | 2201 | break; |
| 2053 | 2202 | case 'reddit': |
| 2054 | 2203 | $link['link'] = esc_url( 'https://reddit.com/submit?url=' . $link['url'] . '&title=' . $link['title'] ); |
| 2055 | - $link['icon'] = '<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><title>ionicons-v5_logos</title><path d="M324,256a36,36,0,1,0,36,36A36,36,0,0,0,324,256Z"/><circle cx="188" cy="292" r="36" transform="translate(-97.43 94.17) rotate(-22.5)"/><path d="M496,253.77c0-31.19-25.14-56.56-56-56.56a55.72,55.72,0,0,0-35.61,12.86c-35-23.77-80.78-38.32-129.65-41.27l22-79L363.15,103c1.9,26.48,24,47.49,50.65,47.49,28,0,50.78-23,50.78-51.21S441,48,413,48c-19.53,0-36.31,11.19-44.85,28.77l-90-17.89L247.05,168.4l-4.63.13c-50.63,2.21-98.34,16.93-134.77,41.53A55.38,55.38,0,0,0,72,197.21c-30.89,0-56,25.37-56,56.56a56.43,56.43,0,0,0,28.11,49.06,98.65,98.65,0,0,0-.89,13.34c.11,39.74,22.49,77,63,105C146.36,448.77,199.51,464,256,464s109.76-15.23,149.83-42.89c40.53-28,62.85-65.27,62.85-105.06a109.32,109.32,0,0,0-.84-13.3A56.32,56.32,0,0,0,496,253.77ZM414,75a24,24,0,1,1-24,24A24,24,0,0,1,414,75ZM42.72,253.77a29.6,29.6,0,0,1,29.42-29.71,29,29,0,0,1,13.62,3.43c-15.5,14.41-26.93,30.41-34.07,47.68A30.23,30.23,0,0,1,42.72,253.77ZM390.82,399c-35.74,24.59-83.6,38.14-134.77,38.14S157,423.61,121.29,399c-33-22.79-51.24-52.26-51.24-83A78.5,78.5,0,0,1,75,288.72c5.68-15.74,16.16-30.48,31.15-43.79a155.17,155.17,0,0,1,14.76-11.53l.3-.21,0,0,.24-.17c35.72-24.52,83.52-38,134.61-38s98.9,13.51,134.62,38l.23.17.34.25A156.57,156.57,0,0,1,406,244.92c15,13.32,25.48,28.05,31.16,43.81a85.44,85.44,0,0,1,4.31,17.67,77.29,77.29,0,0,1,.6,9.65C442.06,346.77,423.86,376.24,390.82,399Zm69.6-123.92c-7.13-17.28-18.56-33.29-34.07-47.72A29.09,29.09,0,0,1,440,224a29.59,29.59,0,0,1,29.41,29.71A30.07,30.07,0,0,1,460.42,275.1Z"/><path d="M323.23,362.22c-.25.25-25.56,26.07-67.15,26.27-42-.2-66.28-25.23-67.31-26.27h0a4.14,4.14,0,0,0-5.83,0l-13.7,13.47a4.15,4.15,0,0,0,0,5.89h0c3.4,3.4,34.7,34.23,86.78,34.45,51.94-.22,83.38-31.05,86.78-34.45h0a4.16,4.16,0,0,0,0-5.9l-13.71-13.47a4.13,4.13,0,0,0-5.81,0Z"/></svg>'; | |
| 2204 | + $link['icon'] = '<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><path d="M324,256a36,36,0,1,0,36,36A36,36,0,0,0,324,256Z"/><circle cx="188" cy="292" r="36" transform="translate(-97.43 94.17) rotate(-22.5)"/><path d="M496,253.77c0-31.19-25.14-56.56-56-56.56a55.72,55.72,0,0,0-35.61,12.86c-35-23.77-80.78-38.32-129.65-41.27l22-79L363.15,103c1.9,26.48,24,47.49,50.65,47.49,28,0,50.78-23,50.78-51.21S441,48,413,48c-19.53,0-36.31,11.19-44.85,28.77l-90-17.89L247.05,168.4l-4.63.13c-50.63,2.21-98.34,16.93-134.77,41.53A55.38,55.38,0,0,0,72,197.21c-30.89,0-56,25.37-56,56.56a56.43,56.43,0,0,0,28.11,49.06,98.65,98.65,0,0,0-.89,13.34c.11,39.74,22.49,77,63,105C146.36,448.77,199.51,464,256,464s109.76-15.23,149.83-42.89c40.53-28,62.85-65.27,62.85-105.06a109.32,109.32,0,0,0-.84-13.3A56.32,56.32,0,0,0,496,253.77ZM414,75a24,24,0,1,1-24,24A24,24,0,0,1,414,75ZM42.72,253.77a29.6,29.6,0,0,1,29.42-29.71,29,29,0,0,1,13.62,3.43c-15.5,14.41-26.93,30.41-34.07,47.68A30.23,30.23,0,0,1,42.72,253.77ZM390.82,399c-35.74,24.59-83.6,38.14-134.77,38.14S157,423.61,121.29,399c-33-22.79-51.24-52.26-51.24-83A78.5,78.5,0,0,1,75,288.72c5.68-15.74,16.16-30.48,31.15-43.79a155.17,155.17,0,0,1,14.76-11.53l.3-.21,0,0,.24-.17c35.72-24.52,83.52-38,134.61-38s98.9,13.51,134.62,38l.23.17.34.25A156.57,156.57,0,0,1,406,244.92c15,13.32,25.48,28.05,31.16,43.81a85.44,85.44,0,0,1,4.31,17.67,77.29,77.29,0,0,1,.6,9.65C442.06,346.77,423.86,376.24,390.82,399Zm69.6-123.92c-7.13-17.28-18.56-33.29-34.07-47.72A29.09,29.09,0,0,1,440,224a29.59,29.59,0,0,1,29.41,29.71A30.07,30.07,0,0,1,460.42,275.1Z"/><path d="M323.23,362.22c-.25.25-25.56,26.07-67.15,26.27-42-.2-66.28-25.23-67.31-26.27h0a4.14,4.14,0,0,0-5.83,0l-13.7,13.47a4.15,4.15,0,0,0,0,5.89h0c3.4,3.4,34.7,34.23,86.78,34.45,51.94-.22,83.38-31.05,86.78-34.45h0a4.16,4.16,0,0,0,0-5.9l-13.71-13.47a4.13,4.13,0,0,0-5.81,0Z"/></svg>'; | |
| 2056 | 2205 | $link['attr_title'] = esc_html__( 'Share on Reddit', 'shopbuilder' ); |
| 2057 | 2206 | $link['social_network'] = 'Reddit'; |
| 2058 | 2207 | $link['social_action'] = 'Share'; |
| 2059 | 2208 | break; |
| @@ -2150,9 +2299,8 @@ | ||
| 2150 | 2299 | return true; |
| 2151 | 2300 | } |
| 2152 | 2301 | } |
| 2153 | 2302 | |
| 2154 | - | |
| 2155 | 2303 | /*** |
| 2156 | 2304 | * Save Settings data |
| 2157 | 2305 | * |
| 2158 | 2306 | * @param $section_id |
| @@ -2164,10 +2312,9 @@ | ||
| 2164 | 2312 | public static function set_options( $section_id = '', $block_id = '', $rawOptions = [] ) { |
| 2165 | 2313 | $section_id = ! empty( $section_id ) ? sanitize_text_field( wp_unslash( $section_id ) ) : ''; |
| 2166 | 2314 | $block_id = ! empty( $block_id ) ? sanitize_text_field( wp_unslash( $block_id ) ) : ''; |
| 2167 | 2315 | $rawOptions = ! empty( $rawOptions ) ? $rawOptions : []; |
| 2168 | - | |
| 2169 | - $results = [ | |
| 2316 | + $results = [ | |
| 2170 | 2317 | 'status' => true, |
| 2171 | 2318 | 'message' => '', |
| 2172 | 2319 | ]; |
| 2173 | 2320 | if ( ! $section_id || ! $block_id ) { |
| @@ -2183,9 +2330,9 @@ | ||
| 2183 | 2330 | |
| 2184 | 2331 | return $results; |
| 2185 | 2332 | } |
| 2186 | 2333 | |
| 2187 | - $options = DataModel::source()->get_option( $section_id, [] ); | |
| 2334 | + $options = DataModel::source()->get_option( $section_id, [], false ); | |
| 2188 | 2335 | $changed = false; |
| 2189 | 2336 | $fields = []; |
| 2190 | 2337 | if ( isset( $sections[ $section_id ]['list'][ $block_id ]['fields'] ) && ! empty( $sections[ $section_id ]['list'][ $block_id ]['fields'] ) ) { |
| 2191 | 2338 | $fields = $sections[ $section_id ]['list'][ $block_id ]['fields']; |
| @@ -2206,12 +2353,40 @@ | ||
| 2206 | 2353 | $field = $fields[ $raw_option_key ]; |
| 2207 | 2354 | if ( $field['type'] === 'switch' ) { |
| 2208 | 2355 | $value = 'on' === $raw_value ? 'on' : ''; |
| 2209 | 2356 | } elseif ( 'repeaters' === $field['type'] ) { |
| 2210 | - $value = stripslashes_deep( $raw_value ); | |
| 2357 | + $the_value = []; | |
| 2358 | + $rep_title = []; | |
| 2359 | + if ( ! empty( $raw_value ) && is_array( $raw_value ) ) { | |
| 2360 | + foreach ( $raw_value as $key => $value ) { | |
| 2361 | + if ( is_string( $value ) ) { | |
| 2362 | + $the_value_decoded = json_decode( stripslashes_deep( $value ) ); | |
| 2363 | + } else { | |
| 2364 | + $the_value_decoded = $value; | |
| 2365 | + } | |
| 2366 | + $cr = $the_value_decoded->title ?? ''; | |
| 2367 | + if ( in_array( $cr, $rep_title, true ) ) { | |
| 2368 | + continue; | |
| 2369 | + } | |
| 2370 | + $rep_title[] = $cr; | |
| 2371 | + $the_value[] = $the_value_decoded; | |
| 2372 | + } | |
| 2373 | + } elseif ( ! empty( $raw_value ) && is_string( $raw_value ) ) { | |
| 2374 | + $the_value = $raw_value; | |
| 2375 | + } | |
| 2376 | + $value = wp_json_encode( $the_value ); | |
| 2377 | + } elseif ( in_array( $field['type'], [ 'product_addons_special_settings', 'checkout_fields' ] ) ) { | |
| 2378 | + $manual_field_value = []; | |
| 2379 | + if ( is_array( $raw_value ) ) { | |
| 2380 | + foreach ( $raw_value as $key => $value ) { | |
| 2381 | + $manual_field_value[] = json_decode( stripslashes( $value ), true ); | |
| 2382 | + } | |
| 2383 | + $value = wp_json_encode( $manual_field_value ); | |
| 2384 | + } elseif ( is_string( $raw_value ) ) { | |
| 2385 | + $value = $raw_value; | |
| 2386 | + } | |
| 2211 | 2387 | } else { |
| 2212 | 2388 | if ( ! empty( $field['multiple'] ) || in_array( $field['type'], [ 'checkbox', 'search_and_multi_select' ] ) ) { |
| 2213 | - | |
| 2214 | 2389 | if ( isset( $raw_value ) && is_array( $raw_value ) ) { |
| 2215 | 2390 | if ( ! empty( $field['sanitize_fn'] ) && is_callable( $field['sanitize_fn'] ) ) { |
| 2216 | 2391 | $value = array_map( $field['sanitize_fn'], $raw_value ); |
| 2217 | 2392 | } else { |
| @@ -2220,10 +2395,16 @@ | ||
| 2220 | 2395 | } else { |
| 2221 | 2396 | $value = []; |
| 2222 | 2397 | } |
| 2223 | 2398 | } else { |
| 2224 | - if ( ! empty( $field['sanitize_fn'] ) && is_callable( $field['sanitize_fn'] ) ) { | |
| 2225 | - $value = $field['sanitize_fn']( $raw_value ); | |
| 2399 | + if ( ! empty( $field['sanitize_fn'] ) ) { | |
| 2400 | + if ( is_callable( $field['sanitize_fn'] ) ) { | |
| 2401 | + $value = $field['sanitize_fn']( $raw_value ); | |
| 2402 | + } elseif ( 'pass_all' === $field['sanitize_fn'] ) { | |
| 2403 | + $value = $raw_value; | |
| 2404 | + } else { | |
| 2405 | + $value = $field['sanitize_fn']( $raw_value ); | |
| 2406 | + } | |
| 2226 | 2407 | } else { |
| 2227 | 2408 | $value = sanitize_text_field( $raw_value ); |
| 2228 | 2409 | } |
| 2229 | 2410 | } |
| @@ -2269,9 +2450,8 @@ | ||
| 2269 | 2450 | * } |
| 2270 | 2451 | * return; |
| 2271 | 2452 | * } |
| 2272 | 2453 | */ |
| 2273 | - | |
| 2274 | 2454 | public static function count_products_by_taxonomies( $terms, $taxonomy = 'product_cat' ) { |
| 2275 | 2455 | if ( empty( $terms ) || ! is_array( $terms ) ) { |
| 2276 | 2456 | return; |
| 2277 | 2457 | } |
| @@ -2287,9 +2467,8 @@ | ||
| 2287 | 2467 | $args['product_tag_id'] = $terms; |
| 2288 | 2468 | } |
| 2289 | 2469 | |
| 2290 | 2470 | $query = new WC_Product_Query( $args ); |
| 2291 | - | |
| 2292 | 2471 | return ! empty( $query->get_products() ) ? count( $query->get_products() ) : 0; |
| 2293 | 2472 | } |
| 2294 | 2473 | |
| 2295 | 2474 | /** |
| @@ -2307,9 +2486,12 @@ | ||
| 2307 | 2486 | if ( 'page' === get_post_type() ) { |
| 2308 | 2487 | return false; |
| 2309 | 2488 | } |
| 2310 | 2489 | |
| 2311 | - $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page ); | |
| 2490 | + $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page ); | |
| 2491 | + if ( ! $id ) { | |
| 2492 | + return false; | |
| 2493 | + } | |
| 2312 | 2494 | $cache_key = 'product_filters_has_ajax_' . $id; |
| 2313 | 2495 | if ( isset( self::$cache[ $cache_key ] ) ) { |
| 2314 | 2496 | return self::$cache[ $cache_key ]; |
| 2315 | 2497 | } |
| @@ -2318,8 +2500,9 @@ | ||
| 2318 | 2500 | |
| 2319 | 2501 | foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) { |
| 2320 | 2502 | $ajax[] = isset( $data['settings']['ajax_mode'] ) ? false : true; |
| 2321 | 2503 | } |
| 2504 | + | |
| 2322 | 2505 | self::$cache[ $cache_key ] = ! empty( $ajax[0] ); |
| 2323 | 2506 | return ! empty( $ajax[0] ); |
| 2324 | 2507 | } |
| 2325 | 2508 | |
| @@ -2337,9 +2520,11 @@ | ||
| 2337 | 2520 | |
| 2338 | 2521 | $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page ); |
| 2339 | 2522 | $elmap = ElementorDataMap::instance(); |
| 2340 | 2523 | $ajax = []; |
| 2341 | - | |
| 2524 | + if ( ! $id ) { | |
| 2525 | + return false; | |
| 2526 | + } | |
| 2342 | 2527 | foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) { |
| 2343 | 2528 | $ajax[] = ! isset( $data['settings']['active_filter'] ); |
| 2344 | 2529 | |
| 2345 | 2530 | } |
| @@ -2363,28 +2548,83 @@ | ||
| 2363 | 2548 | |
| 2364 | 2549 | if ( isset( self::$cache[ $cache_key ] ) ) { |
| 2365 | 2550 | return self::$cache[ $cache_key ]; |
| 2366 | 2551 | } |
| 2552 | + $results = wp_cache_get( $cache_key, 'shopbuilder' ); | |
| 2553 | + if ( ! $results ) { | |
| 2554 | + global $wpdb; | |
| 2555 | + $sql = "SELECT t.term_id, t.name | |
| 2556 | + FROM {$wpdb->terms} t | |
| 2557 | + JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id | |
| 2558 | + WHERE tt.taxonomy = 'product_cat'"; | |
| 2367 | 2559 | |
| 2368 | - $results = wp_cache_get( $cache_key ); | |
| 2560 | + if ( $search_query ) { | |
| 2561 | + $sql .= ' AND t.name LIKE %s'; | |
| 2562 | + $prepared_sql = $wpdb->prepare( $sql, '%' . $wpdb->esc_like( $search_query ) . '%' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared | |
| 2563 | + } else { | |
| 2564 | + $prepared_sql = $sql; // No need for placeholders. | |
| 2565 | + } | |
| 2369 | 2566 | |
| 2567 | + $results = $wpdb->get_results( $prepared_sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared | |
| 2568 | + // Cache the results in the object cache for future use. | |
| 2569 | + wp_cache_set( $cache_key, $results, 'shopbuilder' ); // Adjust the expiration time as needed. | |
| 2570 | + Cache::set_data_cache_key( $cache_key ); | |
| 2571 | + } | |
| 2572 | + | |
| 2573 | + $cats = []; | |
| 2574 | + if ( ! is_array( $results ) && ! count( $results ) ) { | |
| 2575 | + return $cats; | |
| 2576 | + } | |
| 2577 | + foreach ( $results as $row ) { | |
| 2578 | + $category_id = $row->term_id; | |
| 2579 | + $category_title = $row->name; | |
| 2580 | + | |
| 2581 | + $cats[] = [ | |
| 2582 | + 'value' => $category_id, | |
| 2583 | + 'label' => $category_title, | |
| 2584 | + ]; | |
| 2585 | + } | |
| 2586 | + | |
| 2587 | + // Cache the results in a static variable for the next call. | |
| 2588 | + self::$cache[ $cache_key ] = $cats; | |
| 2589 | + return $cats; | |
| 2590 | + } | |
| 2591 | + /** | |
| 2592 | + * Get WooCommerce product categories. | |
| 2593 | + * | |
| 2594 | + * @param string|null $search_query The search string for category names. | |
| 2595 | + * | |
| 2596 | + * @return array An array of product categories with 'value' and 'label' keys. | |
| 2597 | + */ | |
| 2598 | + public static function products_tags_query( $search_query = null ) { | |
| 2599 | + if ( ! is_admin() ) { | |
| 2600 | + return []; | |
| 2601 | + } | |
| 2602 | + | |
| 2603 | + $cache_key = 'rtsb_product_tags_' . md5( serialize( $search_query ) ); | |
| 2604 | + | |
| 2605 | + if ( isset( self::$cache[ $cache_key ] ) ) { | |
| 2606 | + return self::$cache[ $cache_key ]; | |
| 2607 | + } | |
| 2608 | + $results = wp_cache_get( $cache_key, 'shopbuilder' ); | |
| 2370 | 2609 | if ( ! $results ) { |
| 2371 | 2610 | global $wpdb; |
| 2372 | 2611 | $sql = "SELECT t.term_id, t.name |
| 2373 | 2612 | FROM {$wpdb->terms} t |
| 2374 | 2613 | JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id |
| 2375 | - WHERE tt.taxonomy = 'product_cat'"; | |
| 2614 | + WHERE tt.taxonomy = 'product_tag'"; | |
| 2376 | 2615 | |
| 2377 | 2616 | if ( $search_query ) { |
| 2378 | 2617 | $sql .= ' AND t.name LIKE %s'; |
| 2379 | - $prepared_sql = $wpdb->prepare( $sql, '%' . $wpdb->esc_like( $search_query ) . '%' ); // Escaping and wildcard | |
| 2618 | + $prepared_sql = $wpdb->prepare( $sql, '%' . $wpdb->esc_like( $search_query ) . '%' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared | |
| 2380 | 2619 | } else { |
| 2381 | 2620 | $prepared_sql = $sql; // No need for placeholders. |
| 2382 | 2621 | } |
| 2383 | 2622 | |
| 2384 | - $results = $wpdb->get_results( $prepared_sql ); | |
| 2623 | + $results = $wpdb->get_results( $prepared_sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared | |
| 2385 | 2624 | // Cache the results in the object cache for future use. |
| 2386 | - wp_cache_set( $cache_key, $results ); // Adjust the expiration time as needed. | |
| 2625 | + wp_cache_set( $cache_key, $results, 'shopbuilder' ); // Adjust the expiration time as needed. | |
| 2626 | + Cache::set_data_cache_key( $cache_key ); | |
| 2387 | 2627 | } |
| 2388 | 2628 | |
| 2389 | 2629 | $cats = []; |
| 2390 | 2630 | if ( ! is_array( $results ) && ! count( $results ) ) { |
| @@ -2475,8 +2715,9 @@ | ||
| 2475 | 2715 | 'post_type' => 'any', |
| 2476 | 2716 | 'posts_per_page' => 20, |
| 2477 | 2717 | 'orderby' => 'ID', |
| 2478 | 2718 | 'order' => 'DESC', |
| 2719 | + // 'suppress_filters' => false, // WPML Support, Remove Others Languages. | |
| 2479 | 2720 | ] |
| 2480 | 2721 | ); |
| 2481 | 2722 | |
| 2482 | 2723 | if ( 'archive' !== $args['post_type'] ) { |
| @@ -2487,11 +2728,12 @@ | ||
| 2487 | 2728 | $query_results = get_posts( $args ); |
| 2488 | 2729 | foreach ( $query_results as $post ) { |
| 2489 | 2730 | $posts[] = [ |
| 2490 | 2731 | 'value' => $post->ID, |
| 2491 | - 'label' => $post->post_title, | |
| 2732 | + 'label' => $post->post_title . ' (ID#' . $post->ID . ')', | |
| 2492 | 2733 | ]; |
| 2493 | 2734 | } |
| 2735 | + | |
| 2494 | 2736 | if ( $search_query ) { |
| 2495 | 2737 | if ( strpos( '-error 404', $search_query ) ) { |
| 2496 | 2738 | $posts[] = [ |
| 2497 | 2739 | 'value' => 'error', |
| @@ -2498,12 +2740,14 @@ | ||
| 2498 | 2740 | 'label' => __( '404 Error', 'shopbuilder' ), |
| 2499 | 2741 | ]; |
| 2500 | 2742 | } |
| 2501 | 2743 | } else { |
| 2502 | - $posts[] = [ | |
| 2503 | - 'value' => 'error', | |
| 2504 | - 'label' => __( '404 Error', 'shopbuilder' ), | |
| 2505 | - ]; | |
| 2744 | + if ( 'page' === $args['post_type'] ) { | |
| 2745 | + $posts[] = [ | |
| 2746 | + 'value' => 'error', | |
| 2747 | + 'label' => __( '404 Error', 'shopbuilder' ), | |
| 2748 | + ]; | |
| 2749 | + } | |
| 2506 | 2750 | } |
| 2507 | 2751 | } else { |
| 2508 | 2752 | $posts = self::get_registered_post_types( $search_query ); |
| 2509 | 2753 | } |
| @@ -2551,35 +2795,48 @@ | ||
| 2551 | 2795 | } else { |
| 2552 | 2796 | include $view_file; |
| 2553 | 2797 | } |
| 2554 | 2798 | } |
| 2555 | - /** | |
| 2556 | - * @param int $limit Best-selling Base on product Limit. | |
| 2557 | - * @param string $return_type id|Object. | |
| 2558 | - * | |
| 2559 | - * @return int | |
| 2560 | - */ | |
| 2561 | - public static function best_selling_products( $limit = 10, $return_type = 'id' ) { | |
| 2562 | - $cache_key = 'best_selling_products' . $return_type . $limit; | |
| 2563 | 2799 | |
| 2800 | + /** | |
| 2801 | + * Best selling product query. | |
| 2802 | + * | |
| 2803 | + * @param int $minimum_sale Minimum sale/ | |
| 2804 | + * @param int $limit Total limit. | |
| 2805 | + * | |
| 2806 | + * @return array|mixed | |
| 2807 | + */ | |
| 2808 | + public static function best_selling_products_ids( $minimum_sale = 1, $limit = 10 ) { | |
| 2809 | + $cache_key = 'rtsb_best_selling_products_' . $minimum_sale . '_' . $limit; | |
| 2564 | 2810 | // Check if the data is in the cache. |
| 2811 | + if ( isset( self::$cache[ $cache_key ] ) ) { | |
| 2812 | + return self::$cache[ $cache_key ]; | |
| 2813 | + } | |
| 2565 | 2814 | $cached_data = get_transient( $cache_key ); |
| 2566 | 2815 | if ( $cached_data ) { |
| 2816 | + self::$cache[ $cache_key ] = $cached_data; | |
| 2567 | 2817 | return $cached_data; |
| 2568 | 2818 | } |
| 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 | - | |
| 2819 | + global $wpdb; | |
| 2820 | + $sql = $wpdb->prepare( | |
| 2821 | + " | |
| 2822 | + SELECT ID | |
| 2823 | + FROM {$wpdb->posts} AS p | |
| 2824 | + LEFT JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id | |
| 2825 | + WHERE p.post_type = 'product' | |
| 2826 | + AND p.post_status = 'publish' | |
| 2827 | + AND pm.meta_key = 'total_sales' | |
| 2828 | + AND pm.meta_value >= %d | |
| 2829 | + ORDER BY pm.meta_value + 0 DESC | |
| 2830 | + LIMIT %d | |
| 2831 | + ", | |
| 2832 | + $minimum_sale, | |
| 2833 | + $limit | |
| 2834 | + ); | |
| 2835 | + $best_selling = $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared | |
| 2579 | 2836 | // Cache the result for future use. |
| 2580 | 2837 | set_transient( $cache_key, $best_selling, DAY_IN_SECONDS ); |
| 2581 | - | |
| 2838 | + self::$cache[ $cache_key ] = $best_selling; | |
| 2582 | 2839 | return $best_selling; |
| 2583 | 2840 | } |
| 2584 | 2841 | |
| 2585 | 2842 | /** |
| @@ -2602,12 +2859,14 @@ | ||
| 2602 | 2859 | |
| 2603 | 2860 | if ( isset( self::$cache[ $cache_key ] ) ) { |
| 2604 | 2861 | return self::$cache[ $cache_key ]; |
| 2605 | 2862 | } |
| 2863 | + $date_created = $product->get_date_created(); | |
| 2864 | + if ( ! $date_created ) { | |
| 2865 | + return false; | |
| 2866 | + } | |
| 2867 | + $publish_timestamp = strtotime( $date_created->date_i18n( 'Y-m-d H:i:s' ) ); | |
| 2606 | 2868 | |
| 2607 | - // Get the product publish date. | |
| 2608 | - $publish_timestamp = strtotime( $product->get_date_created()->date_i18n( 'Y-m-d H:i:s' ) ); | |
| 2609 | - | |
| 2610 | 2869 | // Calculate the difference in days. |
| 2611 | 2870 | $days_difference = abs( time() - $publish_timestamp ) / ( 60 * 60 * 24 ); |
| 2612 | 2871 | |
| 2613 | 2872 | // Check if the product is considered new. |
| @@ -2630,6 +2889,390 @@ | ||
| 2630 | 2889 | public static function is_guest_feature_disabled( $option, $default ) { |
| 2631 | 2890 | $disabled = self::get_option( 'general', 'guest_user', $option, $default ); |
| 2632 | 2891 | |
| 2633 | 2892 | return ! is_user_logged_in() && $disabled; |
| 2893 | + } | |
| 2894 | + | |
| 2895 | + /** | |
| 2896 | + * Checks if a feature is disabled for guest users based on the provided option. | |
| 2897 | + * | |
| 2898 | + * @param string $option The option to retrieve from the item. | |
| 2899 | + * @param mixed $default The default value if the option is not found. | |
| 2900 | + * | |
| 2901 | + * @return bool | |
| 2902 | + */ | |
| 2903 | + public static function woocommerce_output_all_notices() { | |
| 2904 | + if ( function_exists( 'wc_print_notices' ) ) : | |
| 2905 | + echo '<div class="rtsb-notice">'; | |
| 2906 | + woocommerce_output_all_notices(); | |
| 2907 | + echo '</div>'; | |
| 2908 | + endif; | |
| 2909 | + } | |
| 2910 | + | |
| 2911 | + /** | |
| 2912 | + * @param object $product Product. | |
| 2913 | + * @return bool | |
| 2914 | + */ | |
| 2915 | + public static function is_visible_qty_input( $product = null ) { | |
| 2916 | + $is_visible_qty = true; | |
| 2917 | + if ( $product instanceof \WC_Product ) { | |
| 2918 | + if ( $product->is_sold_individually() ) { | |
| 2919 | + $is_visible_qty = false; | |
| 2920 | + } elseif ( $product->managing_stock() ) { | |
| 2921 | + if ( in_array( $product->get_backorders(), [ 'notify' , 'yes' ], true ) ) { | |
| 2922 | + $is_visible_qty = true; | |
| 2923 | + } elseif ( $product->get_stock_quantity() < 2 ) { | |
| 2924 | + $is_visible_qty = false; | |
| 2925 | + } | |
| 2926 | + } | |
| 2927 | + } | |
| 2928 | + return $is_visible_qty; | |
| 2929 | + } | |
| 2930 | + | |
| 2931 | + /** | |
| 2932 | + * @param int $object_id Object id. | |
| 2933 | + * @param string $element_type element type. | |
| 2934 | + * @param string|null $current_lang null for current language, default for default languages. | |
| 2935 | + * @return false|mixed|null | |
| 2936 | + */ | |
| 2937 | + public static function wpml_object_id( $object_id, $element_type, $current_lang = 'default' ) { | |
| 2938 | + if ( ! defined( 'ICL_SITEPRESS_VERSION' ) ) { | |
| 2939 | + return $object_id; | |
| 2940 | + } | |
| 2941 | + if ( ! $object_id || ! $element_type ) { | |
| 2942 | + return $object_id; | |
| 2943 | + } | |
| 2944 | + if ( 'default' === $current_lang ) { | |
| 2945 | + $lang = apply_filters( 'wpml_default_language', null ); | |
| 2946 | + } else { | |
| 2947 | + $lang = null; | |
| 2948 | + } | |
| 2949 | + return apply_filters( 'wpml_object_id', $object_id, $element_type, false, $lang ); | |
| 2950 | + } | |
| 2951 | + | |
| 2952 | + /** | |
| 2953 | + * @return string | |
| 2954 | + */ | |
| 2955 | + public static function wpml_current_language() { | |
| 2956 | + $current = apply_filters( 'wpml_current_language', null ); | |
| 2957 | + $default = apply_filters( 'wpml_default_language', null ); | |
| 2958 | + return $default !== $current ? $current : null; | |
| 2959 | + } | |
| 2960 | + | |
| 2961 | + /** | |
| 2962 | + * Custom icons. | |
| 2963 | + * | |
| 2964 | + * @return string[] | |
| 2965 | + */ | |
| 2966 | + public static function get_custom_icon_names() { | |
| 2967 | + return [ | |
| 2968 | + 'heart-empty', | |
| 2969 | + 'heart', | |
| 2970 | + 'eye', | |
| 2971 | + 'exchange', | |
| 2972 | + 'plus', | |
| 2973 | + 'minus', | |
| 2974 | + 'avatar', | |
| 2975 | + 'pay', | |
| 2976 | + 'share', | |
| 2977 | + 'clock', | |
| 2978 | + 'check-alt', | |
| 2979 | + 'check', | |
| 2980 | + 'delete', | |
| 2981 | + 'marker', | |
| 2982 | + 'list', | |
| 2983 | + 'list-2', | |
| 2984 | + 'power', | |
| 2985 | + 'cart', | |
| 2986 | + 'cart-2', | |
| 2987 | + 'cart-3', | |
| 2988 | + 'downloads', | |
| 2989 | + 'zoom', | |
| 2990 | + 'user-edit', | |
| 2991 | + 'grid', | |
| 2992 | + 'filter', | |
| 2993 | + 'billing', | |
| 2994 | + 'login', | |
| 2995 | + 'payment', | |
| 2996 | + 'search', | |
| 2997 | + 'edit', | |
| 2998 | + 'coupon', | |
| 2999 | + 'arrows-cw', | |
| 3000 | + 'trash-empty', | |
| 3001 | + ]; | |
| 3002 | + } | |
| 3003 | + | |
| 3004 | + /** | |
| 3005 | + * Retrieve an array of custom icons with their HTML representation. | |
| 3006 | + * | |
| 3007 | + * @return array | |
| 3008 | + */ | |
| 3009 | + public static function get_icons() { | |
| 3010 | + $icon = self::get_custom_icon_names(); | |
| 3011 | + $icons_array = []; | |
| 3012 | + foreach ( $icon as $value ) { | |
| 3013 | + $icons_array[ $value ] = '<i class="rtsb-icon rtsb-icon-' . $value . '"></i> <span class="icon-name">' . ucfirst( str_replace( '-', ' ', $value ) ) . '</span>'; | |
| 3014 | + } | |
| 3015 | + return $icons_array; | |
| 3016 | + } | |
| 3017 | + | |
| 3018 | + /** | |
| 3019 | + * Generates HTML markup for displaying an endpoint icon. | |
| 3020 | + * | |
| 3021 | + * @param array $data The endpoint data containing icon information. | |
| 3022 | + * @param string $endpoint The endpoint identifier. | |
| 3023 | + * @param boolean $wrapper Whether to wrap the icon in a span element. | |
| 3024 | + * | |
| 3025 | + * @return string | |
| 3026 | + */ | |
| 3027 | + public static function get_icon_html( $data, $wrapper = true ) { | |
| 3028 | + if ( empty( $data ) || 'none' === $data['icon_source'] ) { | |
| 3029 | + return ''; | |
| 3030 | + } | |
| 3031 | + $endpoint = ''; | |
| 3032 | + $html = $wrapper ? '<span class="icon ' . esc_attr( $endpoint ) . '_icon">' : ''; | |
| 3033 | + | |
| 3034 | + if ( 'select_icon' === $data['icon_source'] ) { | |
| 3035 | + $html .= '<i class="rtsb-icon rtsb-icon-' . esc_attr( $data['custom_icon'] ) . '"></i>'; | |
| 3036 | + } else { | |
| 3037 | + $icon_html = ''; | |
| 3038 | + $icon_url = $data['image_icon']['source'] ?? ''; | |
| 3039 | + $icon_id = $data['image_icon']['id'] ?? 0; | |
| 3040 | + $extension = ! empty( $icon_url ) ? strtolower( substr( strrchr( $data['image_icon']['source'], '.' ), 1 ) ) : ''; | |
| 3041 | + | |
| 3042 | + if ( 'svg' === $extension ) { | |
| 3043 | + $content = file_get_contents( $icon_url ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents | |
| 3044 | + $is_svg = strpos( $content, '<svg' ); | |
| 3045 | + | |
| 3046 | + if ( false !== $is_svg ) { | |
| 3047 | + $icon_html = substr( $content, $is_svg ); | |
| 3048 | + } | |
| 3049 | + } else { | |
| 3050 | + $attr = [ | |
| 3051 | + 'class' => 'rtsb-icon-img', | |
| 3052 | + 'alt' => esc_html( ucfirst( $endpoint ) ) . esc_html__( ' Icon', 'shopbuilder' ), | |
| 3053 | + ]; | |
| 3054 | + | |
| 3055 | + $icon_html = wp_get_attachment_image( absint( $icon_id ), 'full', true, $attr ); | |
| 3056 | + } | |
| 3057 | + | |
| 3058 | + $html .= $icon_html; | |
| 3059 | + } | |
| 3060 | + | |
| 3061 | + $html .= $wrapper ? '</span>' : ''; | |
| 3062 | + | |
| 3063 | + return $html; | |
| 3064 | + } | |
| 3065 | + /** | |
| 3066 | + * Flushes rewrite rules. | |
| 3067 | + * | |
| 3068 | + * @return void | |
| 3069 | + */ | |
| 3070 | + public static function maybe_flush_rewrite_rules() { | |
| 3071 | + add_action( 'wp_loaded', [ __CLASS__, 'flush_rewrite_rules' ] ); | |
| 3072 | + add_action( 'shutdown', [ __CLASS__, 'flush_rewrite_rules_once_more' ] ); | |
| 3073 | + } | |
| 3074 | + | |
| 3075 | + /** | |
| 3076 | + * Flushes rewrite rules if needed. | |
| 3077 | + * | |
| 3078 | + * @return void | |
| 3079 | + */ | |
| 3080 | + public static function flush_rewrite_rules() { | |
| 3081 | + if ( get_option( 'rtsb_permalinks_need_flush' ) === 'yes' ) { | |
| 3082 | + flush_rewrite_rules(); | |
| 3083 | + } | |
| 3084 | + | |
| 3085 | + if ( get_option( 'rtsb_permalinks_flushed' ) === 'yes' ) { | |
| 3086 | + flush_rewrite_rules(); | |
| 3087 | + delete_option( 'rtsb_permalinks_flushed' ); | |
| 3088 | + } | |
| 3089 | + } | |
| 3090 | + | |
| 3091 | + /** | |
| 3092 | + * Flushes rewrite rules if needed for second time. | |
| 3093 | + * | |
| 3094 | + * @return void | |
| 3095 | + */ | |
| 3096 | + public static function flush_rewrite_rules_once_more() { | |
| 3097 | + if ( get_option( 'rtsb_permalinks_need_flush' ) === 'yes' ) { | |
| 3098 | + flush_rewrite_rules(); | |
| 3099 | + update_option( 'rtsb_permalinks_flushed', 'yes' ); | |
| 3100 | + delete_option( 'rtsb_permalinks_need_flush' ); | |
| 3101 | + } | |
| 3102 | + } | |
| 3103 | + | |
| 3104 | + /** | |
| 3105 | + * Social Share Platforms. | |
| 3106 | + * | |
| 3107 | + * @return mixed|null | |
| 3108 | + */ | |
| 3109 | + public static function set_repeater_options( $section_id, $block_id, $option_key, $compare_key, $compare_value, $values ) { | |
| 3110 | + // $options = self::get_options( $section_id, $block_id ); | |
| 3111 | + $modules = DataModel::source()->get_option( $section_id, [], false ); | |
| 3112 | + if ( empty( $modules[ $block_id ] ) ) { | |
| 3113 | + return; | |
| 3114 | + } | |
| 3115 | + $options = $modules[ $block_id ]; | |
| 3116 | + if ( empty( $options[ $option_key ] ) ) { | |
| 3117 | + return; | |
| 3118 | + } | |
| 3119 | + $repeater_options = json_decode( $options[ $option_key ], true ); | |
| 3120 | + // Check if options are not empty and are in array format. | |
| 3121 | + if ( ! is_array( $repeater_options ) ) { | |
| 3122 | + return; | |
| 3123 | + } | |
| 3124 | + // Use array_column to get an array of values from $compare_key. | |
| 3125 | + $column_values = array_column( $repeater_options, $compare_key ); | |
| 3126 | + // Use array_search to find the index of the $compare_value. | |
| 3127 | + $index = array_search( $compare_value, $column_values, true ); | |
| 3128 | + if ( false === $index ) { | |
| 3129 | + return; | |
| 3130 | + } | |
| 3131 | + $repeater_options[ $index ] = wp_parse_args( $values, $repeater_options[ $index ] ); | |
| 3132 | + $options[ $option_key ] = wp_json_encode( $repeater_options ); | |
| 3133 | + $modules[ $block_id ] = $options; | |
| 3134 | + DataModel::source()->set_option( $section_id, $modules ); | |
| 3135 | + } | |
| 3136 | + | |
| 3137 | + | |
| 3138 | + /** | |
| 3139 | + * @param array $ids products id. | |
| 3140 | + * @return array | |
| 3141 | + */ | |
| 3142 | + public static function get_available_products_by_ids( $ids = [] ) { | |
| 3143 | + $ids = array_filter( | |
| 3144 | + $ids, | |
| 3145 | + function ( $id ) { | |
| 3146 | + return 'product' === get_post_type( $id ) && 'publish' === get_post_status( $id ); | |
| 3147 | + } | |
| 3148 | + ); | |
| 3149 | + return $ids; | |
| 3150 | + } | |
| 3151 | + | |
| 3152 | + /** | |
| 3153 | + * Generate and cache dynamic CSS styles. | |
| 3154 | + * | |
| 3155 | + * @param array $options CSS options to apply (e.g. padding, margin). | |
| 3156 | + * @param string $cache_key Cache key for the CSS. | |
| 3157 | + * @param array $css_properties An array of CSS properties with selectors and properties. | |
| 3158 | + * @param string $style_handle The handle for the inline styles. | |
| 3159 | + * | |
| 3160 | + * @return void | |
| 3161 | + */ | |
| 3162 | + public static function dynamic_styles( $options, $cache_key, $css_properties, $style_handle = 'rtsb-frontend' ) { | |
| 3163 | + $cached_css = wp_cache_get( $cache_key, 'shopbuilder' ); | |
| 3164 | + | |
| 3165 | + if ( false !== $cached_css ) { | |
| 3166 | + wp_add_inline_style( $style_handle, $cached_css ); | |
| 3167 | + return; | |
| 3168 | + } | |
| 3169 | + | |
| 3170 | + $css_rules = []; | |
| 3171 | + $grouped_css_rules = []; | |
| 3172 | + | |
| 3173 | + foreach ( $css_properties as $option => $details ) { | |
| 3174 | + if ( ! empty( $options[ $option ] ) ) { | |
| 3175 | + $selector = $details['selector'] ?? ''; | |
| 3176 | + $property = $details['property'] ?? ''; | |
| 3177 | + $unit = $details['unit'] ?? ''; | |
| 3178 | + $value = $options[ $option ]; | |
| 3179 | + | |
| 3180 | + if ( empty( $grouped_css_rules[ $selector ] ) ) { | |
| 3181 | + $grouped_css_rules[ $selector ] = []; | |
| 3182 | + } | |
| 3183 | + | |
| 3184 | + if ( is_array( $property ) ) { | |
| 3185 | + foreach ( $property as $prop ) { | |
| 3186 | + $grouped_css_rules[ $selector ][] = $prop . ': ' . $value . $unit . ' !important'; | |
| 3187 | + } | |
| 3188 | + } else { | |
| 3189 | + $grouped_css_rules[ $selector ][] = $property . ': ' . $value . $unit . ' !important'; | |
| 3190 | + } | |
| 3191 | + } | |
| 3192 | + } | |
| 3193 | + | |
| 3194 | + foreach ( $grouped_css_rules as $selector => $properties ) { | |
| 3195 | + $css_rules[] = $selector . ' {' . implode( '; ', $properties ) . '}'; | |
| 3196 | + } | |
| 3197 | + | |
| 3198 | + $dynamic_css = implode( ' ', $css_rules ); | |
| 3199 | + | |
| 3200 | + wp_cache_set( $cache_key, $dynamic_css, 'shopbuilder', 12 * HOUR_IN_SECONDS ); | |
| 3201 | + Cache::set_data_cache_key( $cache_key ); | |
| 3202 | + | |
| 3203 | + if ( ! empty( $dynamic_css ) ) { | |
| 3204 | + wp_add_inline_style( $style_handle, $dynamic_css ); | |
| 3205 | + } | |
| 3206 | + } | |
| 3207 | + | |
| 3208 | + /** | |
| 3209 | + * Pro version notice. | |
| 3210 | + * | |
| 3211 | + * @param string $ver Pro Version. | |
| 3212 | + * | |
| 3213 | + * @return array[] | |
| 3214 | + */ | |
| 3215 | + public static function pro_version_notice( $ver, $tab = 'billing_fields', $name = 'ShopBuilder', $enable_free_Link = true ) { | |
| 3216 | + return [ | |
| 3217 | + 'version_check' => [ | |
| 3218 | + 'id' => 'version_check', | |
| 3219 | + 'type' => 'title', | |
| 3220 | + 'label' => sprintf( | |
| 3221 | + /* translators: 1: required version, 2: link to the Plugins page */ | |
| 3222 | + esc_html__( | |
| 3223 | + 'To access all features and settings of this module, please ensure that "%1$s" is updated to version %2$s. %3$s', | |
| 3224 | + 'shopbuilder' | |
| 3225 | + ), | |
| 3226 | + $name, | |
| 3227 | + sprintf( | |
| 3228 | + '<br /><u><b>%s</b></u>', | |
| 3229 | + esc_html( $ver ?? '1.5.0' ) . ' or higher' | |
| 3230 | + ), | |
| 3231 | + $enable_free_Link | |
| 3232 | + ? sprintf( | |
| 3233 | + '%s <a class="pro-update-required" href="%s" target="_blank" title="%s">%s</a>', | |
| 3234 | + esc_attr__( 'Update to the latest version', 'shopbuilder' ), | |
| 3235 | + esc_url( admin_url( 'plugins.php' ) ), | |
| 3236 | + esc_attr__( 'Go to the Plugin Page', 'shopbuilder' ), | |
| 3237 | + esc_html__( 'from the Plugins page', 'shopbuilder' ) | |
| 3238 | + ) | |
| 3239 | + : '' | |
| 3240 | + ), | |
| 3241 | + 'tab' => $tab, | |
| 3242 | + 'customClass' => 'checkout-notice', | |
| 3243 | + ], | |
| 3244 | + ]; | |
| 3245 | + } | |
| 3246 | + | |
| 3247 | + /** | |
| 3248 | + * Get product gallery ids. | |
| 3249 | + * | |
| 3250 | + * @param object $product Product object. | |
| 3251 | + * | |
| 3252 | + * @return mixed | |
| 3253 | + */ | |
| 3254 | + public static function get_cached_gallery_ids( $product ) { | |
| 3255 | + $product_id = $product->get_id(); | |
| 3256 | + $cache_key = 'rtsb_product_gallery_ids_' . $product_id; | |
| 3257 | + | |
| 3258 | + if ( isset( self::$cache[ $cache_key ] ) ) { | |
| 3259 | + return self::$cache[ $cache_key ]; | |
| 3260 | + } | |
| 3261 | + | |
| 3262 | + $cached_result = wp_cache_get( $cache_key, 'shopbuilder' ); | |
| 3263 | + | |
| 3264 | + if ( false !== $cached_result ) { | |
| 3265 | + self::$cache[ $cache_key ] = $cached_result; | |
| 3266 | + | |
| 3267 | + return $cached_result; | |
| 3268 | + } | |
| 3269 | + | |
| 3270 | + $gallery_ids = $product->get_gallery_image_ids(); | |
| 3271 | + self::$cache[ $cache_key ] = $gallery_ids; | |
| 3272 | + | |
| 3273 | + wp_cache_set( $cache_key, $gallery_ids, 'shopbuilder', 12 * HOUR_IN_SECONDS ); | |
| 3274 | + Cache::set_data_cache_key( $cache_key ); | |
| 3275 | + | |
| 3276 | + return $gallery_ids; | |
| 2634 | 3277 | } |
| 2635 | 3278 | } |