| @@ -11,14 +11,15 @@ | ||
| 11 | 11 | if ( ! defined( 'ABSPATH' ) ) { |
| 12 | 12 | exit( 'This script cannot be accessed directly.' ); |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | +use WC_Product; | |
| 16 | +use WC_Product_Query; | |
| 15 | 17 | use Elementor\Icons_Manager; |
| 16 | 18 | use RadiusTheme\SB\Models\ReSizer; |
| 17 | 19 | use RadiusTheme\SB\Models\DataModel; |
| 18 | 20 | use RadiusTheme\SB\Models\ModuleList; |
| 19 | 21 | use RadiusTheme\SB\Models\Settings; |
| 20 | -use WC_Product; | |
| 21 | 22 | |
| 22 | 23 | /** |
| 23 | 24 | * Fns class |
| 24 | 25 | */ |
| @@ -24,8 +25,13 @@ | ||
| 24 | 25 | */ |
| 25 | 26 | class Fns { |
| 26 | 27 | |
| 27 | 28 | /** |
| 29 | + * @var array | |
| 30 | + */ | |
| 31 | + private static $cache = []; | |
| 32 | + | |
| 33 | + /** | |
| 28 | 34 | * Verify nonce. |
| 29 | 35 | * |
| 30 | 36 | * @return bool |
| 31 | 37 | */ |
| @@ -38,9 +44,55 @@ | ||
| 38 | 44 | |
| 39 | 45 | return false; |
| 40 | 46 | } |
| 41 | 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 | + | |
| 42 | 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 | + /** | |
| 43 | 95 | * @param $plugin_slug |
| 44 | 96 | * |
| 45 | 97 | * @return bool |
| 46 | 98 | */ |
| @@ -61,9 +113,46 @@ | ||
| 61 | 113 | } |
| 62 | 114 | |
| 63 | 115 | return false; |
| 64 | 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' ); | |
| 65 | 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 | + | |
| 66 | 155 | /** |
| 67 | 156 | * @param $data |
| 68 | 157 | * |
| 69 | 158 | * @return mixed|string |
| @@ -68,14 +157,25 @@ | ||
| 68 | 157 | * |
| 69 | 158 | * @return mixed|string |
| 70 | 159 | */ |
| 71 | 160 | public static function stripslashes_value( $data ) { |
| 72 | - if ( is_string( $data ) && strpos( $data, '\\' ) !== false ) { | |
| 73 | - return stripslashes( $data ); | |
| 74 | - } elseif ( is_array( $data ) ) { | |
| 161 | + if ( is_array( $data ) ) { | |
| 75 | 162 | foreach ( $data as $key => $value ) { |
| 76 | 163 | $data[ $key ] = self::stripslashes_value( $value ); |
| 77 | 164 | } |
| 165 | + } elseif ( is_string( $data ) ) { | |
| 166 | + $trimmed = trim( $data ); | |
| 167 | + // Try to decode JSON. | |
| 168 | + $json = json_decode( $trimmed, true ); | |
| 169 | + if ( json_last_error() === JSON_ERROR_NONE && is_array( $json ) ) { | |
| 170 | + // Recursively stripslashes on decoded array. | |
| 171 | + $json = self::stripslashes_value( $json ); | |
| 172 | + return wp_json_encode( $json, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); | |
| 173 | + } | |
| 174 | + // Not valid JSON, just stripslashes if needed. | |
| 175 | + if ( strpos( $data, '\\' ) !== false ) { | |
| 176 | + return stripslashes( $data ); | |
| 177 | + } | |
| 78 | 178 | } |
| 79 | 179 | |
| 80 | 180 | return $data; |
| 81 | 181 | } |
| @@ -114,14 +214,15 @@ | ||
| 114 | 214 | |
| 115 | 215 | /** |
| 116 | 216 | * @param string $template_name Template name. |
| 117 | 217 | * @param string $template_path Template path. (default: ''). |
| 118 | - * @param string $plugin_path Plugin path. (default: ''). fallback file from plugin | |
| 218 | + * @param string $plugin_path Plugin path. (default: ''). fallback file from plugin. | |
| 119 | 219 | * |
| 120 | 220 | * @return mixed|void |
| 121 | 221 | */ |
| 122 | 222 | public static function locate_template( $template_name, $template_path = '', $plugin_path = '' ) { |
| 123 | - $template_name = $template_name . '.php'; | |
| 223 | + $template_name = self::sanitize_file_name( $template_name ) . '.php'; | |
| 224 | + | |
| 124 | 225 | if ( ! $template_path ) { |
| 125 | 226 | $template_path = rtsb()->get_template_path(); |
| 126 | 227 | } |
| 127 | 228 | if ( ! $plugin_path ) { |
| @@ -164,8 +265,19 @@ | ||
| 164 | 265 | return apply_filters( 'rtsb/core/locate_template', $located, $template_name ); |
| 165 | 266 | } |
| 166 | 267 | |
| 167 | 268 | /** |
| 269 | + * Remove any character that is not alphanumeric, /, _, or -. | |
| 270 | + * | |
| 271 | + * @param string $name Name to sanitize. | |
| 272 | + * | |
| 273 | + * @return array|string|string[]|null | |
| 274 | + */ | |
| 275 | + private static function sanitize_file_name( $name ) { | |
| 276 | + return preg_replace( '/[^a-zA-Z0-9\/_\-]/', '', $name ); | |
| 277 | + } | |
| 278 | + | |
| 279 | + /** | |
| 168 | 280 | * Template Content |
| 169 | 281 | * |
| 170 | 282 | * @param string $template_name Template name. |
| 171 | 283 | * @param array $args Arguments. (default: array). |
| @@ -175,10 +287,19 @@ | ||
| 175 | 287 | * |
| 176 | 288 | * @return false|string|void |
| 177 | 289 | */ |
| 178 | 290 | 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 | - | |
| 291 | + $cache_key = sanitize_key( implode( '-', [ 'template', $template_name, $template_path ] ) ); | |
| 292 | + $located = (string) wp_cache_get( $cache_key, 'shopbuilder' ); | |
| 293 | + if ( ! $located ) { | |
| 294 | + $located = self::locate_template( $template_name, $template_path, $plugin_path ); | |
| 295 | + // Don't cache the absolute path so that it can be shared between web servers with different paths. | |
| 296 | + $cache_path = wc_tokenize_path( $located, wc_get_path_define_tokens() ); | |
| 297 | + Cache::set_template_cache( $cache_key, $cache_path ); | |
| 298 | + } else { | |
| 299 | + // Make sure that the absolute path to the template is resolved. | |
| 300 | + $located = wc_untokenize_path( $located, wc_get_path_define_tokens() ); | |
| 301 | + } | |
| 181 | 302 | if ( ! file_exists( $located ) ) { |
| 182 | 303 | // translators: %s template. |
| 183 | 304 | self::doing_it_wrong( __FUNCTION__, sprintf( __( '%s does not exist.', 'shopbuilder' ), '<code>' . $located . '</code>' ), '1.0' ); |
| 184 | 305 | |
| @@ -186,9 +307,9 @@ | ||
| 186 | 307 | } |
| 187 | 308 | |
| 188 | 309 | if ( ! empty( $args ) && is_array( $args ) ) { |
| 189 | 310 | $atts = $args; |
| 190 | - extract( $args ); // @codingStandardsIgnoreLine | |
| 311 | + extract( $args ); // @codingStandardsIgnoreLine | |
| 191 | 312 | } |
| 192 | 313 | |
| 193 | 314 | // Allow 3rd party plugin filter template file from their plugin. |
| 194 | 315 | $located = apply_filters( 'rtsb/core/get_template', $located, $template_name, $args ); |
| @@ -198,8 +319,9 @@ | ||
| 198 | 319 | } |
| 199 | 320 | |
| 200 | 321 | do_action( 'rtsb/core/before_template_part', $template_name, $located, $args ); |
| 201 | 322 | include $located; |
| 323 | + | |
| 202 | 324 | do_action( 'rtsb/core/after_template_part', $template_name, $located, $args ); |
| 203 | 325 | |
| 204 | 326 | if ( $return ) { |
| 205 | 327 | return ob_get_clean(); |
| @@ -302,9 +424,9 @@ | ||
| 302 | 424 | // Return the Builder Template id. |
| 303 | 425 | |
| 304 | 426 | if ( get_post_type( get_the_ID() ) == BuilderFns::$post_type_tb ) { |
| 305 | 427 | $product_id = get_post_meta( get_the_ID(), BuilderFns::$product_template_meta, true ); |
| 306 | - if ( $product_id ) { | |
| 428 | + if ( $product_id && get_post_status( $product_id ) ) { | |
| 307 | 429 | return $product_id; |
| 308 | 430 | } |
| 309 | 431 | } |
| 310 | 432 | |
| @@ -309,15 +431,16 @@ | ||
| 309 | 431 | } |
| 310 | 432 | |
| 311 | 433 | global $wpdb; |
| 312 | 434 | $cache_key = 'rtsb_prepared_product_id'; |
| 313 | - $_post_id = wp_cache_get( $cache_key ); | |
| 314 | - | |
| 435 | + $_post_id = wp_cache_get( $cache_key, 'shopbuilder' ); | |
| 315 | 436 | if ( false === $_post_id || 'publish' !== get_post_status( $_post_id ) ) { |
| 437 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery | |
| 316 | 438 | $_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' ) | |
| 439 | + $wpdb->prepare( "SELECT MAX(ID) FROM {$wpdb->prefix}posts WHERE post_type = %s AND post_status IN('publish', 'draft')", 'product' ) | |
| 318 | 440 | ); |
| 319 | - wp_cache_set( $cache_key, $_post_id, '', 12 * HOUR_IN_SECONDS ); | |
| 441 | + wp_cache_set( $cache_key, $_post_id, 'shopbuilder', 12 * HOUR_IN_SECONDS ); | |
| 442 | + Cache::set_data_cache_key( $cache_key ); | |
| 320 | 443 | } |
| 321 | 444 | |
| 322 | 445 | return $_post_id; |
| 323 | 446 | } |
| @@ -322,19 +445,27 @@ | ||
| 322 | 445 | return $_post_id; |
| 323 | 446 | } |
| 324 | 447 | |
| 325 | 448 | /** |
| 326 | - * Get the product function. | |
| 449 | + * Get the product function. Only used in single page widgets. | |
| 327 | 450 | * |
| 328 | 451 | * @return object |
| 329 | 452 | */ |
| 330 | 453 | public static function get_product() { |
| 331 | - global $post, $product; | |
| 454 | + global $product; | |
| 455 | + | |
| 332 | 456 | if ( is_singular( 'product' ) && $product instanceof WC_Product ) { |
| 457 | + // do_action( 'rtsb_before_product_template_render' );. | |
| 333 | 458 | return $product; |
| 334 | 459 | } |
| 335 | - | |
| 336 | - return wc_get_product( self::get_prepared_product_id() ); | |
| 460 | + $cache_key = 'prepared_product_for_preview'; | |
| 461 | + if ( isset( self::$cache[ $cache_key ] ) ) { | |
| 462 | + return self::$cache[ $cache_key ]; | |
| 463 | + } | |
| 464 | + $product = wc_get_product( self::get_prepared_product_id() ); | |
| 465 | + self::$cache[ $cache_key ] = $product; | |
| 466 | + do_action( 'rtsb_before_product_template_render' ); | |
| 467 | + return $product; | |
| 337 | 468 | } |
| 338 | 469 | |
| 339 | 470 | /** |
| 340 | 471 | * Error function |
| @@ -345,10 +476,11 @@ | ||
| 345 | 476 | * |
| 346 | 477 | * @return void |
| 347 | 478 | */ |
| 348 | 479 | public static function doing_it_wrong( $function, $message, $version ) { |
| 480 | + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_wp_debug_backtrace_summary | |
| 349 | 481 | $message .= ' Backtrace: ' . wp_debug_backtrace_summary(); |
| 350 | - _doing_it_wrong( $function, $message, $version ); | |
| 482 | + _doing_it_wrong( esc_html( $function ), wp_kses_post( $message ), esc_html( $version ) ); | |
| 351 | 483 | } |
| 352 | 484 | |
| 353 | 485 | /** |
| 354 | 486 | * @return array |
| @@ -479,13 +611,14 @@ | ||
| 479 | 611 | } |
| 480 | 612 | |
| 481 | 613 | if ( strlen( $page_content ) > 0 ) { |
| 482 | 614 | // Search for an existing page with the specified page content (typically a shortcode). |
| 483 | - $shortcode = str_replace( [ '<!-- wp:shortcode -->', '<!-- /wp:shortcode -->' ], '', $page_content ); | |
| 615 | + $shortcode = str_replace( [ '<!-- wp:shortcode -->', '<!-- /wp:shortcode -->' ], '', $page_content ); | |
| 616 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 484 | 617 | $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 | 618 | } else { |
| 486 | 619 | // 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 ) ); | |
| 620 | + $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 | |
| 488 | 621 | } |
| 489 | 622 | |
| 490 | 623 | $valid_page_found = apply_filters( 'rtsb/core/create_page_id', $valid_page_found, $slug, $page_content, $options ); |
| 491 | 624 | |
| @@ -507,12 +640,12 @@ | ||
| 507 | 640 | |
| 508 | 641 | // Search for a matching valid trashed page. |
| 509 | 642 | if ( strlen( $page_content ) > 0 ) { |
| 510 | 643 | // 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}%" ) ); | |
| 644 | + $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 | |
| 512 | 645 | } else { |
| 513 | 646 | // 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 ) ); | |
| 647 | + $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 | |
| 515 | 648 | } |
| 516 | 649 | |
| 517 | 650 | if ( $trashed_page_found ) { |
| 518 | 651 | $page_id = $trashed_page_found; |
| @@ -883,8 +1016,51 @@ | ||
| 883 | 1016 | return $allowed_html; |
| 884 | 1017 | } |
| 885 | 1018 | |
| 886 | 1019 | /** |
| 1020 | + * Safe get a validated HTML tag. | |
| 1021 | + * | |
| 1022 | + * @param string $tag HTML tag. | |
| 1023 | + * | |
| 1024 | + * @return string | |
| 1025 | + */ | |
| 1026 | + public static function get_validated_html_tag( $tag ) { | |
| 1027 | + $allowed_html_wrapper_tags = [ | |
| 1028 | + 'a', | |
| 1029 | + 'article', | |
| 1030 | + 'aside', | |
| 1031 | + 'button', | |
| 1032 | + 'div', | |
| 1033 | + 'footer', | |
| 1034 | + 'h1', | |
| 1035 | + 'h2', | |
| 1036 | + 'h3', | |
| 1037 | + 'h4', | |
| 1038 | + 'h5', | |
| 1039 | + 'h6', | |
| 1040 | + 'header', | |
| 1041 | + 'main', | |
| 1042 | + 'nav', | |
| 1043 | + 'p', | |
| 1044 | + 'section', | |
| 1045 | + 'span', | |
| 1046 | + ]; | |
| 1047 | + | |
| 1048 | + return in_array( strtolower( $tag ), $allowed_html_wrapper_tags, true ) ? $tag : 'div'; | |
| 1049 | + } | |
| 1050 | + | |
| 1051 | + /** | |
| 1052 | + * Safe print a validated HTML tag. | |
| 1053 | + * | |
| 1054 | + * @param string $tag HTML tag. | |
| 1055 | + * | |
| 1056 | + * @return void | |
| 1057 | + */ | |
| 1058 | + public static function print_validated_html_tag( $tag ) { | |
| 1059 | + self::print_html( self::get_validated_html_tag( $tag ) ); | |
| 1060 | + } | |
| 1061 | + | |
| 1062 | + /** | |
| 887 | 1063 | * Insert Some array element |
| 888 | 1064 | * |
| 889 | 1065 | * @param [type] $key The elements will insert nearby this key. |
| 890 | 1066 | * @param [type] $main_array Original array. |
| @@ -979,10 +1155,19 @@ | ||
| 979 | 1155 | |
| 980 | 1156 | if ( empty( $taxonomy ) ) { |
| 981 | 1157 | return $terms; |
| 982 | 1158 | } |
| 1159 | + $cache_key = 'rtsb_get_all_terms_by_tax_name_' . $taxonomy; | |
| 1160 | + if ( isset( self::$cache[ $cache_key ] ) ) { | |
| 1161 | + return self::$cache[ $cache_key ]; | |
| 1162 | + } | |
| 983 | 1163 | |
| 984 | - $termList = get_terms( [ $taxonomy ], [ 'hide_empty' => 0 ] ); | |
| 1164 | + $termList = get_terms( | |
| 1165 | + [ | |
| 1166 | + 'taxonomy' => $taxonomy, | |
| 1167 | + 'hide_empty' => false, | |
| 1168 | + ] | |
| 1169 | + ); | |
| 985 | 1170 | |
| 986 | 1171 | if ( is_array( $termList ) && ! empty( $termList ) && empty( $termList['errors'] ) ) { |
| 987 | 1172 | if ( $placeholder ) { |
| 988 | 1173 | $terms = [ |
| @@ -993,11 +1178,28 @@ | ||
| 993 | 1178 | foreach ( $termList as $term ) { |
| 994 | 1179 | $terms[ $term->term_id ] = esc_html( $term->name ); |
| 995 | 1180 | } |
| 996 | 1181 | } |
| 997 | - | |
| 1182 | + self::$cache[ $cache_key ] = $terms; | |
| 998 | 1183 | return $terms; |
| 999 | 1184 | } |
| 1185 | + /** | |
| 1186 | + * Get all product attribute taxonomy by id | |
| 1187 | + * | |
| 1188 | + * @param array $term_ids Term id. | |
| 1189 | + * | |
| 1190 | + * @return array | |
| 1191 | + */ | |
| 1192 | + public static function tax_filter_attr_taxonomy( $term_ids ) { | |
| 1193 | + $taxonomies = []; | |
| 1194 | + foreach ( $term_ids as $id ) { | |
| 1195 | + $term = get_term( $id ); | |
| 1196 | + if ( ! is_wp_error( $term ) && $term ) { | |
| 1197 | + $taxonomies[] = $term->taxonomy; | |
| 1198 | + } | |
| 1199 | + } | |
| 1200 | + return array_unique( $taxonomies ); | |
| 1201 | + } | |
| 1000 | 1202 | |
| 1001 | 1203 | /** |
| 1002 | 1204 | * Get all terms by attributes |
| 1003 | 1205 | * |
| @@ -1011,9 +1213,9 @@ | ||
| 1011 | 1213 | |
| 1012 | 1214 | if ( $attributes ) { |
| 1013 | 1215 | foreach ( $attributes as $tax ) { |
| 1014 | 1216 | if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) ) { |
| 1015 | - $termList[ $tax->attribute_name ] = get_terms( wc_attribute_taxonomy_name( $tax->attribute_name ), 'orderby=name&hide_empty=0' ); | |
| 1217 | + $termList[ $tax->attribute_name ] = get_terms( wc_attribute_taxonomy_name( $tax->attribute_name ) ); | |
| 1016 | 1218 | } |
| 1017 | 1219 | } |
| 1018 | 1220 | } |
| 1019 | 1221 | |
| @@ -1105,8 +1307,12 @@ | ||
| 1105 | 1307 | * |
| 1106 | 1308 | * @return int|array |
| 1107 | 1309 | */ |
| 1108 | 1310 | public static function get_terms( $taxonomy, $first_term = false, $only_parents = false, $return_slug = false ) { |
| 1311 | + if ( ! is_admin() ) { | |
| 1312 | + return []; | |
| 1313 | + } | |
| 1314 | + | |
| 1109 | 1315 | // TODO:: Return Slug always true for all settings. |
| 1110 | 1316 | $term_list = []; |
| 1111 | 1317 | $args = [ |
| 1112 | 1318 | 'taxonomy' => $taxonomy, |
| @@ -1158,9 +1364,9 @@ | ||
| 1158 | 1364 | } |
| 1159 | 1365 | |
| 1160 | 1366 | $html .= '<div class="product-rating">'; |
| 1161 | 1367 | $html .= wc_get_rating_html( $average_rating, $rating_count ); |
| 1162 | - $html .= ! empty( $html ) ? '<span class="count">(' . $average_rating . ')</span>' : ''; | |
| 1368 | + $html .= ! empty( $html ) ? '<span class="rtsb-count">(' . $average_rating . ')</span>' : ''; | |
| 1163 | 1369 | $html .= '</div>'; |
| 1164 | 1370 | |
| 1165 | 1371 | self::print_html( $html, true ); |
| 1166 | 1372 | |
| @@ -1171,15 +1377,15 @@ | ||
| 1171 | 1377 | return ''; |
| 1172 | 1378 | } |
| 1173 | 1379 | |
| 1174 | 1380 | $preset = ! empty( $args['preset'] ) ? $args['preset'] : 'preset1'; |
| 1175 | - $average = $args['show_average_rating'] ? '<span class="count">(' . $average_rating . ')</span>' : ''; | |
| 1381 | + $average = $args['show_average_rating'] ? '<span class="rtsb-count">(' . $average_rating . ')</span>' : ''; | |
| 1176 | 1382 | $count = ''; |
| 1177 | 1383 | |
| 1178 | 1384 | if ( $args['show_rating_count'] ) { |
| 1179 | - $count .= '<div class="count">'; | |
| 1385 | + $count .= '<div class="rtsb-count">'; | |
| 1180 | 1386 | $count .= sprintf( |
| 1181 | - /* translators: %s is the number of reviews */ | |
| 1387 | + /* translators: %s is the number of reviews */ | |
| 1182 | 1388 | _n( '%s Review', '%s Reviews', $rating_count, 'shopbuilder' ), |
| 1183 | 1389 | $rating_count |
| 1184 | 1390 | ); |
| 1185 | 1391 | $count .= '</div>'; |
| @@ -1204,8 +1410,23 @@ | ||
| 1204 | 1410 | |
| 1205 | 1411 | self::print_html( $html, true ); |
| 1206 | 1412 | } |
| 1207 | 1413 | |
| 1414 | + public static function get_product_simple_rating_html() { | |
| 1415 | + global $product; | |
| 1416 | + $html = null; | |
| 1417 | + $rating_count = $product->get_rating_count(); | |
| 1418 | + $average_rating = $product->get_average_rating(); | |
| 1419 | + $html .= '<div class="product-rating">'; | |
| 1420 | + $html .= wc_get_rating_html( $average_rating, $rating_count ); | |
| 1421 | + $html .= ! empty( $html ) ? '<span class="rtsb-count">(' . $average_rating . ')</span>' : ''; | |
| 1422 | + $html .= '</div>'; | |
| 1423 | + | |
| 1424 | + self::print_html( $html, true ); | |
| 1425 | + } | |
| 1426 | + | |
| 1427 | + | |
| 1428 | + | |
| 1208 | 1429 | /** |
| 1209 | 1430 | * Text truncation. |
| 1210 | 1431 | * |
| 1211 | 1432 | * @param string $text_to_truncate Text. |
| @@ -1248,8 +1469,14 @@ | ||
| 1248 | 1469 | * |
| 1249 | 1470 | * @return void |
| 1250 | 1471 | */ |
| 1251 | 1472 | public static function get_badge_html( $text, $class = 'fill' ) { |
| 1473 | + if ( self::is_module_active( 'product_badges' ) && 'rtsb_yes' === $text ) { | |
| 1474 | + do_action( 'rtsb/modules/product_badges/frontend/display' ); | |
| 1475 | + | |
| 1476 | + return; | |
| 1477 | + } | |
| 1478 | + | |
| 1252 | 1479 | if ( empty( $text ) ) { |
| 1253 | 1480 | return; |
| 1254 | 1481 | } |
| 1255 | 1482 | ob_start(); |
| @@ -1256,10 +1483,9 @@ | ||
| 1256 | 1483 | ?> |
| 1257 | 1484 | |
| 1258 | 1485 | <ul class="rtsb-promotion-list"> |
| 1259 | 1486 | <li class="rtsb-promotion-list-item"> |
| 1260 | - <span | |
| 1261 | - class="rtsb-tag-<?php echo ! empty( $class ) ? esc_attr( $class ) : ''; ?>"><?php echo esc_html( $text ); ?></span> | |
| 1487 | + <span class="rtsb-tag-<?php echo ! empty( $class ) ? esc_attr( $class ) : ''; ?>"><?php echo esc_html( $text ); ?></span> | |
| 1262 | 1488 | </li> |
| 1263 | 1489 | </ul> |
| 1264 | 1490 | |
| 1265 | 1491 | <?php |
| @@ -1297,10 +1523,42 @@ | ||
| 1297 | 1523 | |
| 1298 | 1524 | <?php |
| 1299 | 1525 | self::print_html( ob_get_clean() ); |
| 1300 | 1526 | } |
| 1527 | + /** | |
| 1528 | + * Brands HTML | |
| 1529 | + * | |
| 1530 | + * @param int $id Product ID. | |
| 1531 | + * @param string $class Custom class. | |
| 1532 | + * | |
| 1533 | + * @return void|string | |
| 1534 | + */ | |
| 1535 | + public static function get_brands_list( $id, $class = 'rtsb-brand-outline' ) { | |
| 1536 | + $terms = get_the_terms( $id, 'product_brand' ); | |
| 1537 | + if ( empty( $id ) || empty( $terms ) || is_wp_error( $terms ) ) { | |
| 1538 | + return ''; | |
| 1539 | + } | |
| 1540 | + ob_start(); | |
| 1541 | + ?> | |
| 1301 | 1542 | |
| 1543 | + <ul class="rtsb-brand-list <?php echo esc_attr( $class ); ?>"> | |
| 1544 | + <?php | |
| 1545 | + $brand_list = get_the_term_list( | |
| 1546 | + $id, | |
| 1547 | + 'product_brand', | |
| 1548 | + '<li class="rtsb-brand-list-item">', | |
| 1549 | + '</li><li class="rtsb-brand-list-item">', | |
| 1550 | + '</li>' | |
| 1551 | + ); | |
| 1302 | 1552 | |
| 1553 | + self::print_html( $brand_list ); | |
| 1554 | + ?> | |
| 1555 | + </ul> | |
| 1556 | + | |
| 1557 | + <?php | |
| 1558 | + self::print_html( ob_get_clean() ); | |
| 1559 | + } | |
| 1560 | + | |
| 1303 | 1561 | /** |
| 1304 | 1562 | * Get Featured Image HTML. |
| 1305 | 1563 | * |
| 1306 | 1564 | * @param string $type Image type. |
| @@ -1310,12 +1568,13 @@ | ||
| 1310 | 1568 | * @param array $custom_img_size Custom image size. |
| 1311 | 1569 | * @param bool $lazy Lazy load check. |
| 1312 | 1570 | * @param bool $hover Hover image. |
| 1313 | 1571 | * @param bool $gallery Gallery image. |
| 1572 | + * @param bool $custom_image_id Custom category image ID. | |
| 1314 | 1573 | * |
| 1315 | 1574 | * @return string|null |
| 1316 | 1575 | */ |
| 1317 | - 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 ) { | |
| 1576 | + public static function get_product_image_html( $type = 'product', $post_id = null, $f_img_size = 'medium', $default_img_id = null, $custom_img_size = [], $lazy = false, $hover = false, $gallery = false, $custom_image_id = 0 ) { | |
| 1318 | 1577 | $img_html = null; |
| 1319 | 1578 | $attachment_id = null; |
| 1320 | 1579 | $c_size = false; |
| 1321 | 1580 | $hover_class = ''; |
| @@ -1339,9 +1598,9 @@ | ||
| 1339 | 1598 | if ( 'product' === $type ) { |
| 1340 | 1599 | $a_id = get_post_thumbnail_id( $post_id ); |
| 1341 | 1600 | $post_title = get_the_title( $post_id ); |
| 1342 | 1601 | } elseif ( 'category' === $type ) { |
| 1343 | - $a_id = get_term_meta( $post_id, 'thumbnail_id', true ); | |
| 1602 | + $a_id = $custom_image_id ? $custom_image_id : get_term_meta( $post_id, 'thumbnail_id', true ); | |
| 1344 | 1603 | $post_title = get_term( $post_id )->name; |
| 1345 | 1604 | } else { |
| 1346 | 1605 | $a_id = $default_img_id; |
| 1347 | 1606 | } |
| @@ -1491,8 +1750,20 @@ | ||
| 1491 | 1750 | * |
| 1492 | 1751 | * @return string |
| 1493 | 1752 | */ |
| 1494 | 1753 | public static function icons_manager( $control, $class = '', $builder = 'elementor' ): string { |
| 1754 | + if ( empty( $control['value'] ) ) { | |
| 1755 | + return ''; | |
| 1756 | + } | |
| 1757 | + if ( is_array( $control['value'] ) ) { | |
| 1758 | + $cache_key = 'icons_managet_' . str_replace( ' ', '', md5( serialize( $control['value'] ) ) ); | |
| 1759 | + } else { | |
| 1760 | + $cache_key = 'icons_managet_' . str_replace( ' ', '', $control['value'] ); | |
| 1761 | + } | |
| 1762 | + if ( isset( self::$cache[ $cache_key ] ) ) { | |
| 1763 | + return self::$cache[ $cache_key ]; | |
| 1764 | + } | |
| 1765 | + | |
| 1495 | 1766 | $attributes = [ |
| 1496 | 1767 | 'aria-hidden' => 'true', |
| 1497 | 1768 | ]; |
| 1498 | 1769 | |
| @@ -1505,9 +1776,11 @@ | ||
| 1505 | 1776 | if ( defined( 'ELEMENTOR_VERSION' ) && ! empty( $control ) && 'elementor' === $builder ) { |
| 1506 | 1777 | Icons_Manager::render_icon( $control, $attributes ); |
| 1507 | 1778 | } |
| 1508 | 1779 | |
| 1509 | - return ob_get_clean(); | |
| 1780 | + $icons = ob_get_clean(); | |
| 1781 | + self::$cache[ $cache_key ] = $icons; | |
| 1782 | + return $icons; | |
| 1510 | 1783 | } |
| 1511 | 1784 | |
| 1512 | 1785 | /** |
| 1513 | 1786 | * Get product swatches. |
| @@ -1545,14 +1818,95 @@ | ||
| 1545 | 1818 | if ( ! $product->is_on_sale() ) { |
| 1546 | 1819 | return ''; |
| 1547 | 1820 | } |
| 1548 | 1821 | |
| 1549 | - $badge_text = ''; | |
| 1822 | + $badge_text = ''; | |
| 1823 | + $percentage = self::calculate_sale_percentage( $product ); | |
| 1824 | + | |
| 1825 | + if ( $percentage > 0 ) { | |
| 1826 | + $badge_text = '-' . round( $percentage ) . '%'; | |
| 1827 | + } | |
| 1828 | + | |
| 1829 | + if ( 'text' === $type ) { | |
| 1830 | + $badge_text = $text; | |
| 1831 | + } | |
| 1832 | + | |
| 1833 | + return $badge_text; | |
| 1834 | + } | |
| 1835 | + | |
| 1836 | + /** | |
| 1837 | + * Get sale badge | |
| 1838 | + * | |
| 1839 | + * @param object $product Product Object. | |
| 1840 | + * @param string $type Badge type. | |
| 1841 | + * @param string $text Badge text. | |
| 1842 | + * @param string $out_of_stock_text Out of stock text. | |
| 1843 | + * | |
| 1844 | + * @return string | |
| 1845 | + */ | |
| 1846 | + public static function get_promo_badge( $product, $type, $text, $out_of_stock_text ) { | |
| 1847 | + $disable_badges = self::get_option( 'general', 'guest_user', 'hide_badges', '' ); | |
| 1848 | + $badges_visibility = rtsb()->has_pro() && ! is_user_logged_in() && $disable_badges; | |
| 1849 | + | |
| 1850 | + if ( $badges_visibility ) { | |
| 1851 | + return ''; | |
| 1852 | + } | |
| 1853 | + | |
| 1854 | + if ( is_null( $product ) ) { | |
| 1855 | + global $product; | |
| 1856 | + } | |
| 1857 | + | |
| 1858 | + if ( ! $product instanceof WC_Product ) { | |
| 1859 | + return ''; | |
| 1860 | + } | |
| 1861 | + | |
| 1862 | + if ( ! $product->is_in_stock() ) { | |
| 1863 | + return $out_of_stock_text; | |
| 1864 | + } | |
| 1865 | + | |
| 1866 | + if ( ! $product->is_on_sale() ) { | |
| 1867 | + return ''; | |
| 1868 | + } | |
| 1869 | + | |
| 1870 | + $badge_text = ''; | |
| 1871 | + $percentage = self::calculate_sale_percentage( $product ); | |
| 1872 | + | |
| 1873 | + if ( $percentage > 0 ) { | |
| 1874 | + $badge_text = '-' . round( $percentage ) . '%'; | |
| 1875 | + } | |
| 1876 | + | |
| 1877 | + if ( 'text' === $type ) { | |
| 1878 | + $badge_text = $text; | |
| 1879 | + } | |
| 1880 | + | |
| 1881 | + return $badge_text; | |
| 1882 | + } | |
| 1883 | + | |
| 1884 | + /** | |
| 1885 | + * Calculate Sale Percentage | |
| 1886 | + * | |
| 1887 | + * @param object $product Product object. | |
| 1888 | + * | |
| 1889 | + * @return float|int|string | |
| 1890 | + */ | |
| 1891 | + public static function calculate_sale_percentage( $product = null ) { | |
| 1892 | + if ( is_null( $product ) ) { | |
| 1893 | + global $product; | |
| 1894 | + } | |
| 1895 | + | |
| 1896 | + if ( ! $product instanceof WC_Product ) { | |
| 1897 | + return ''; | |
| 1898 | + } | |
| 1899 | + | |
| 1900 | + if ( ! $product->is_on_sale() ) { | |
| 1901 | + return ''; | |
| 1902 | + } | |
| 1903 | + | |
| 1550 | 1904 | $percentage = null; |
| 1551 | 1905 | $max_percentage = ''; |
| 1552 | 1906 | |
| 1553 | 1907 | if ( $product->is_type( 'simple' ) ) { |
| 1554 | - $max_percentage = ( ( $product->get_regular_price() - $product->get_sale_price() ) / $product->get_regular_price() ) * 100; | |
| 1908 | + $max_percentage = $product->get_sale_price() ? ( ( $product->get_regular_price() - $product->get_sale_price() ) / $product->get_regular_price() ) * 100 : 0; | |
| 1555 | 1909 | } elseif ( $product->is_type( 'variable' ) ) { |
| 1556 | 1910 | $max_percentage = 0; |
| 1557 | 1911 | |
| 1558 | 1912 | foreach ( $product->get_children() as $child_id ) { |
| @@ -1572,16 +1926,12 @@ | ||
| 1572 | 1926 | } |
| 1573 | 1927 | } |
| 1574 | 1928 | |
| 1575 | 1929 | if ( $max_percentage > 0 ) { |
| 1576 | - $badge_text = '-' . round( $max_percentage ) . '%'; | |
| 1930 | + return round( $max_percentage ); | |
| 1577 | 1931 | } |
| 1578 | 1932 | |
| 1579 | - if ( 'text' === $type ) { | |
| 1580 | - $badge_text = $text; | |
| 1581 | - } | |
| 1582 | - | |
| 1583 | - return $badge_text; | |
| 1933 | + return 0; | |
| 1584 | 1934 | } |
| 1585 | 1935 | |
| 1586 | 1936 | /** |
| 1587 | 1937 | * Pagination |
| @@ -1592,10 +1942,10 @@ | ||
| 1592 | 1942 | * |
| 1593 | 1943 | * @return string |
| 1594 | 1944 | */ |
| 1595 | 1945 | public static function custom_pagination( $pages = '', $range = 4, $ajax = false ) { |
| 1596 | - $html = null; | |
| 1597 | - $showitems = ( $range * 2 ) + 1; | |
| 1946 | + $html = null; | |
| 1947 | + $visible_range = apply_filters( 'rtsb/elements/pagination/visible_range', ( $range * 2 ) + 1 ); | |
| 1598 | 1948 | |
| 1599 | 1949 | global $paged; |
| 1600 | 1950 | |
| 1601 | 1951 | if ( is_front_page() ) { |
| @@ -1623,8 +1973,9 @@ | ||
| 1623 | 1973 | |
| 1624 | 1974 | if ( $ajax ) { |
| 1625 | 1975 | $ajaxClass = ' rtsb-pagination-ajax'; |
| 1626 | 1976 | $dataAttr = "data-paged='1'"; |
| 1977 | + $dataAttr .= ' data-visible-range="' . esc_attr( $visible_range ) . '"'; | |
| 1627 | 1978 | } |
| 1628 | 1979 | |
| 1629 | 1980 | if ( 1 !== $pages ) { |
| 1630 | 1981 | $html .= '<div class="rtsb-pagination' . $ajaxClass . '" ' . $dataAttr . '>'; |
| @@ -1629,29 +1980,29 @@ | ||
| 1629 | 1980 | if ( 1 !== $pages ) { |
| 1630 | 1981 | $html .= '<div class="rtsb-pagination' . $ajaxClass . '" ' . $dataAttr . '>'; |
| 1631 | 1982 | $html .= '<ul class="pagination-list">'; |
| 1632 | 1983 | |
| 1633 | - if ( $paged > 2 && $paged > $range + 1 && $showitems < $pages ) { | |
| 1984 | + if ( $paged > 2 && $paged > $visible_range + 1 && $visible_range < $pages ) { | |
| 1634 | 1985 | $html .= "<li><a data-paged='1' href='" . get_pagenum_link( 1 ) . "' aria-label='First'>«</a></li>"; |
| 1635 | 1986 | } |
| 1636 | 1987 | |
| 1637 | - if ( $paged > 1 && $showitems < $pages ) { | |
| 1988 | + if ( $paged > 1 && $visible_range < $pages ) { | |
| 1638 | 1989 | $p = $paged - 1; |
| 1639 | 1990 | $html .= "<li><a data-paged='{$p}' href='" . get_pagenum_link( $p ) . "' aria-label='Previous'>‹</a></li>"; |
| 1640 | 1991 | } |
| 1641 | 1992 | |
| 1642 | 1993 | for ( $i = 1; $i <= $pages; $i++ ) { |
| 1643 | - if ( 1 != $pages && ( ! ( $i >= $paged + $range + 1 || $i <= $paged - $range - 1 ) || $pages <= $showitems ) ) { | |
| 1994 | + if ( 1 != $pages && ( ! ( $i >= $paged + $visible_range + 1 || $i <= $paged - $visible_range - 1 ) || $pages <= $visible_range ) ) { | |
| 1644 | 1995 | $html .= ( $paged == $i ) ? '<li class="active"><span>' . $i . '</span></li>' : "<li><a data-paged='{$i}' href='" . get_pagenum_link( $i ) . "'>" . $i . '</a></li>'; |
| 1645 | 1996 | } |
| 1646 | 1997 | } |
| 1647 | 1998 | |
| 1648 | - if ( $paged < $pages && $showitems < $pages ) { | |
| 1999 | + if ( $paged < $pages && $visible_range < $pages ) { | |
| 1649 | 2000 | $p = $paged + 1; |
| 1650 | 2001 | $html .= "<li><a data-paged='{$p}' href=\"" . get_pagenum_link( $paged + 1 ) . "\" aria-label='Next'>›</a></li>"; |
| 1651 | 2002 | } |
| 1652 | 2003 | |
| 1653 | - if ( $paged < $pages - 1 && $paged + $range - 1 < $pages && $showitems < $pages ) { | |
| 2004 | + if ( $paged < $pages - 1 && $paged + $range - 1 < $pages && $visible_range < $pages ) { | |
| 1654 | 2005 | $html .= "<li><a data-paged='{$pages}' href='" . get_pagenum_link( $pages ) . "' aria-label='Last'>»</a></li>"; |
| 1655 | 2006 | } |
| 1656 | 2007 | |
| 1657 | 2008 | $html .= '</ul>'; |
| @@ -1910,9 +2261,9 @@ | ||
| 1910 | 2261 | $link['social_action'] = 'Share'; |
| 1911 | 2262 | break; |
| 1912 | 2263 | case 'reddit': |
| 1913 | 2264 | $link['link'] = esc_url( 'https://reddit.com/submit?url=' . $link['url'] . '&title=' . $link['title'] ); |
| 1914 | - $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>'; | |
| 2265 | + $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>'; | |
| 1915 | 2266 | $link['attr_title'] = esc_html__( 'Share on Reddit', 'shopbuilder' ); |
| 1916 | 2267 | $link['social_network'] = 'Reddit'; |
| 1917 | 2268 | $link['social_action'] = 'Share'; |
| 1918 | 2269 | break; |
| @@ -2009,9 +2360,8 @@ | ||
| 2009 | 2360 | return true; |
| 2010 | 2361 | } |
| 2011 | 2362 | } |
| 2012 | 2363 | |
| 2013 | - | |
| 2014 | 2364 | /*** |
| 2015 | 2365 | * Save Settings data |
| 2016 | 2366 | * |
| 2017 | 2367 | * @param $section_id |
| @@ -2023,10 +2373,9 @@ | ||
| 2023 | 2373 | public static function set_options( $section_id = '', $block_id = '', $rawOptions = [] ) { |
| 2024 | 2374 | $section_id = ! empty( $section_id ) ? sanitize_text_field( wp_unslash( $section_id ) ) : ''; |
| 2025 | 2375 | $block_id = ! empty( $block_id ) ? sanitize_text_field( wp_unslash( $block_id ) ) : ''; |
| 2026 | 2376 | $rawOptions = ! empty( $rawOptions ) ? $rawOptions : []; |
| 2027 | - | |
| 2028 | - $results = [ | |
| 2377 | + $results = [ | |
| 2029 | 2378 | 'status' => true, |
| 2030 | 2379 | 'message' => '', |
| 2031 | 2380 | ]; |
| 2032 | 2381 | if ( ! $section_id || ! $block_id ) { |
| @@ -2042,9 +2391,9 @@ | ||
| 2042 | 2391 | |
| 2043 | 2392 | return $results; |
| 2044 | 2393 | } |
| 2045 | 2394 | |
| 2046 | - $options = DataModel::source()->get_option( $section_id, [] ); | |
| 2395 | + $options = DataModel::source()->get_option( $section_id, [], false ); | |
| 2047 | 2396 | $changed = false; |
| 2048 | 2397 | $fields = []; |
| 2049 | 2398 | if ( isset( $sections[ $section_id ]['list'][ $block_id ]['fields'] ) && ! empty( $sections[ $section_id ]['list'][ $block_id ]['fields'] ) ) { |
| 2050 | 2399 | $fields = $sections[ $section_id ]['list'][ $block_id ]['fields']; |
| @@ -2065,12 +2414,40 @@ | ||
| 2065 | 2414 | $field = $fields[ $raw_option_key ]; |
| 2066 | 2415 | if ( $field['type'] === 'switch' ) { |
| 2067 | 2416 | $value = 'on' === $raw_value ? 'on' : ''; |
| 2068 | 2417 | } elseif ( 'repeaters' === $field['type'] ) { |
| 2069 | - $value = stripslashes_deep( $raw_value ); | |
| 2418 | + $the_value = []; | |
| 2419 | + $rep_title = []; | |
| 2420 | + if ( ! empty( $raw_value ) && is_array( $raw_value ) ) { | |
| 2421 | + foreach ( $raw_value as $key => $value ) { | |
| 2422 | + if ( is_string( $value ) ) { | |
| 2423 | + $the_value_decoded = json_decode( stripslashes_deep( $value ) ); | |
| 2424 | + } else { | |
| 2425 | + $the_value_decoded = $value; | |
| 2426 | + } | |
| 2427 | + $cr = $the_value_decoded->title ?? ''; | |
| 2428 | + if ( in_array( $cr, $rep_title, true ) ) { | |
| 2429 | + continue; | |
| 2430 | + } | |
| 2431 | + $rep_title[] = $cr; | |
| 2432 | + $the_value[] = $the_value_decoded; | |
| 2433 | + } | |
| 2434 | + } elseif ( ! empty( $raw_value ) && is_string( $raw_value ) ) { | |
| 2435 | + $the_value = $raw_value; | |
| 2436 | + } | |
| 2437 | + $value = wp_json_encode( $the_value ); | |
| 2438 | + } elseif ( in_array( $field['type'], [ 'product_addons_special_settings', 'checkout_fields' ] ) ) { | |
| 2439 | + $manual_field_value = []; | |
| 2440 | + if ( is_array( $raw_value ) ) { | |
| 2441 | + foreach ( $raw_value as $key => $value ) { | |
| 2442 | + $manual_field_value[] = json_decode( stripslashes( $value ), true ); | |
| 2443 | + } | |
| 2444 | + $value = wp_json_encode( $manual_field_value ); | |
| 2445 | + } elseif ( is_string( $raw_value ) ) { | |
| 2446 | + $value = $raw_value; | |
| 2447 | + } | |
| 2070 | 2448 | } else { |
| 2071 | 2449 | if ( ! empty( $field['multiple'] ) || in_array( $field['type'], [ 'checkbox', 'search_and_multi_select' ] ) ) { |
| 2072 | - | |
| 2073 | 2450 | if ( isset( $raw_value ) && is_array( $raw_value ) ) { |
| 2074 | 2451 | if ( ! empty( $field['sanitize_fn'] ) && is_callable( $field['sanitize_fn'] ) ) { |
| 2075 | 2452 | $value = array_map( $field['sanitize_fn'], $raw_value ); |
| 2076 | 2453 | } else { |
| @@ -2079,10 +2456,16 @@ | ||
| 2079 | 2456 | } else { |
| 2080 | 2457 | $value = []; |
| 2081 | 2458 | } |
| 2082 | 2459 | } else { |
| 2083 | - if ( ! empty( $field['sanitize_fn'] ) && is_callable( $field['sanitize_fn'] ) ) { | |
| 2084 | - $value = $field['sanitize_fn']( $raw_value ); | |
| 2460 | + if ( ! empty( $field['sanitize_fn'] ) ) { | |
| 2461 | + if ( is_callable( $field['sanitize_fn'] ) ) { | |
| 2462 | + $value = $field['sanitize_fn']( $raw_value ); | |
| 2463 | + } elseif ( 'pass_all' === $field['sanitize_fn'] ) { | |
| 2464 | + $value = $raw_value; | |
| 2465 | + } else { | |
| 2466 | + $value = $field['sanitize_fn']( $raw_value ); | |
| 2467 | + } | |
| 2085 | 2468 | } else { |
| 2086 | 2469 | $value = sanitize_text_field( $raw_value ); |
| 2087 | 2470 | } |
| 2088 | 2471 | } |
| @@ -2128,36 +2511,72 @@ | ||
| 2128 | 2511 | * } |
| 2129 | 2512 | * return; |
| 2130 | 2513 | * } |
| 2131 | 2514 | */ |
| 2132 | - | |
| 2133 | 2515 | public static function count_products_by_taxonomies( $terms, $taxonomy = 'product_cat' ) { |
| 2134 | 2516 | if ( empty( $terms ) || ! is_array( $terms ) ) { |
| 2135 | 2517 | return; |
| 2136 | 2518 | } |
| 2137 | 2519 | |
| 2138 | - $category_ids = array_map( | |
| 2139 | - function ( $name ) { | |
| 2140 | - return sanitize_title( $name ); | |
| 2141 | - }, | |
| 2142 | - $terms | |
| 2143 | - ); | |
| 2520 | + $args = [ | |
| 2521 | + 'limit' => -1, | |
| 2522 | + 'return' => 'ids', | |
| 2523 | + ]; | |
| 2144 | 2524 | |
| 2525 | + if ( 'product_cat' === $taxonomy ) { | |
| 2526 | + $args['product_category_id'] = $terms; | |
| 2527 | + } elseif ( 'product_brand' === $taxonomy ) { | |
| 2528 | + $args['product_brand_id'] = $terms; | |
| 2529 | + } else { | |
| 2530 | + $args['product_tag_id'] = $terms; | |
| 2531 | + } | |
| 2532 | + | |
| 2533 | + $query = new WC_Product_Query( $args ); | |
| 2534 | + return ! empty( $query->get_products() ) ? count( $query->get_products() ) : 0; | |
| 2535 | + } | |
| 2536 | + public static function count_products_by_attribute_terms( $term_ids, $relation = 'AND' ) { | |
| 2537 | + if ( empty( $term_ids ) || ! is_array( $term_ids ) ) { | |
| 2538 | + return 0; | |
| 2539 | + } | |
| 2540 | + | |
| 2541 | + $terms_by_taxonomy = []; | |
| 2542 | + | |
| 2543 | + foreach ( $term_ids as $term_id ) { | |
| 2544 | + $term = get_term( $term_id ); | |
| 2545 | + if ( ! is_wp_error( $term ) && $term ) { | |
| 2546 | + if ( ! isset( $terms_by_taxonomy[ $term->taxonomy ] ) ) { | |
| 2547 | + $terms_by_taxonomy[ $term->taxonomy ] = []; | |
| 2548 | + } | |
| 2549 | + $terms_by_taxonomy[ $term->taxonomy ][] = $term_id; | |
| 2550 | + } | |
| 2551 | + } | |
| 2552 | + | |
| 2553 | + if ( empty( $terms_by_taxonomy ) ) { | |
| 2554 | + return 0; | |
| 2555 | + } | |
| 2556 | + | |
| 2145 | 2557 | $args = [ |
| 2146 | - 'post_type' => 'product', | |
| 2147 | - 'posts_per_page' => - 1, | |
| 2148 | - 'tax_query' => [ | |
| 2149 | - [ | |
| 2150 | - 'taxonomy' => $taxonomy, | |
| 2151 | - 'field' => 'term_id', | |
| 2152 | - 'terms' => $category_ids, | |
| 2153 | - ], | |
| 2558 | + 'status' => 'publish', | |
| 2559 | + 'limit' => -1, | |
| 2560 | + 'return' => 'ids', | |
| 2561 | + 'tax_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query | |
| 2562 | + 'relation' => strtoupper( $relation ), | |
| 2154 | 2563 | ], |
| 2155 | 2564 | ]; |
| 2156 | 2565 | |
| 2157 | - $query = new \WP_Query( $args ); | |
| 2566 | + foreach ( $terms_by_taxonomy as $taxonomy => $terms ) { | |
| 2567 | + $args['tax_query'][] = [ | |
| 2568 | + 'taxonomy' => $taxonomy, | |
| 2569 | + 'field' => 'term_id', | |
| 2570 | + 'terms' => $terms, | |
| 2571 | + 'operator' => 'IN', | |
| 2572 | + ]; | |
| 2573 | + } | |
| 2158 | 2574 | |
| 2159 | - return $query->found_posts; | |
| 2575 | + $query = new WC_Product_Query( $args ); | |
| 2576 | + $products = $query->get_products(); | |
| 2577 | + | |
| 2578 | + return count( $products ); | |
| 2160 | 2579 | } |
| 2161 | 2580 | |
| 2162 | 2581 | /** |
| 2163 | 2582 | * Check if product filters widget has ajax. |
| @@ -2170,9 +2589,20 @@ | ||
| 2170 | 2589 | if ( empty( $page ) ) { |
| 2171 | 2590 | return false; |
| 2172 | 2591 | } |
| 2173 | 2592 | |
| 2174 | - $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page ); | |
| 2593 | + if ( 'page' === get_post_type() ) { | |
| 2594 | + return false; | |
| 2595 | + } | |
| 2596 | + | |
| 2597 | + $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page ); | |
| 2598 | + if ( ! $id ) { | |
| 2599 | + return false; | |
| 2600 | + } | |
| 2601 | + $cache_key = 'product_filters_has_ajax_' . $id; | |
| 2602 | + if ( isset( self::$cache[ $cache_key ] ) ) { | |
| 2603 | + return self::$cache[ $cache_key ]; | |
| 2604 | + } | |
| 2175 | 2605 | $elmap = ElementorDataMap::instance(); |
| 2176 | 2606 | $ajax = []; |
| 2177 | 2607 | |
| 2178 | 2608 | foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) { |
| @@ -2178,8 +2608,9 @@ | ||
| 2178 | 2608 | foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) { |
| 2179 | 2609 | $ajax[] = isset( $data['settings']['ajax_mode'] ) ? false : true; |
| 2180 | 2610 | } |
| 2181 | 2611 | |
| 2612 | + self::$cache[ $cache_key ] = ! empty( $ajax[0] ); | |
| 2182 | 2613 | return ! empty( $ajax[0] ); |
| 2183 | 2614 | } |
| 2184 | 2615 | |
| 2185 | 2616 | /** |
| @@ -2196,9 +2627,11 @@ | ||
| 2196 | 2627 | |
| 2197 | 2628 | $id = BuilderFns::is_builder_preview() ? get_the_ID() : BuilderFns::builder_page_id_by_type( $page ); |
| 2198 | 2629 | $elmap = ElementorDataMap::instance(); |
| 2199 | 2630 | $ajax = []; |
| 2200 | - | |
| 2631 | + if ( ! $id ) { | |
| 2632 | + return false; | |
| 2633 | + } | |
| 2201 | 2634 | foreach ( $elmap->get_widget_data( 'rtsb-ajax-product-filters', [], $id ) as $data ) { |
| 2202 | 2635 | $ajax[] = ! isset( $data['settings']['active_filter'] ); |
| 2203 | 2636 | |
| 2204 | 2637 | } |
| @@ -2213,24 +2646,94 @@ | ||
| 2213 | 2646 | * |
| 2214 | 2647 | * @return array An array of product categories with 'value' and 'label' keys. |
| 2215 | 2648 | */ |
| 2216 | 2649 | public static function products_category_query( $search_query = null ) { |
| 2217 | - global $wpdb; | |
| 2650 | + if ( ! is_admin() ) { | |
| 2651 | + return []; | |
| 2652 | + } | |
| 2218 | 2653 | |
| 2219 | - $sql = "SELECT t.term_id, t.name | |
| 2654 | + $cache_key = 'rtsb_product_categories_' . md5( serialize( $search_query ) ); | |
| 2655 | + | |
| 2656 | + if ( isset( self::$cache[ $cache_key ] ) ) { | |
| 2657 | + return self::$cache[ $cache_key ]; | |
| 2658 | + } | |
| 2659 | + $results = wp_cache_get( $cache_key, 'shopbuilder' ); | |
| 2660 | + if ( ! $results ) { | |
| 2661 | + global $wpdb; | |
| 2662 | + $sql = "SELECT t.term_id, t.name | |
| 2220 | 2663 | FROM {$wpdb->terms} t |
| 2221 | 2664 | JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id |
| 2222 | 2665 | WHERE tt.taxonomy = 'product_cat'"; |
| 2223 | 2666 | |
| 2224 | - if ( $search_query ) { | |
| 2225 | - $sql .= ' AND t.name LIKE %s'; | |
| 2226 | - $prepared_sql = $wpdb->prepare( $sql, '%' . $wpdb->esc_like( $search_query ) . '%' ); // Escaping and wildcard | |
| 2227 | - } else { | |
| 2228 | - $prepared_sql = $sql; // No need for placeholders | |
| 2667 | + if ( $search_query ) { | |
| 2668 | + $sql .= ' AND t.name LIKE %s'; | |
| 2669 | + $prepared_sql = $wpdb->prepare( $sql, '%' . $wpdb->esc_like( $search_query ) . '%' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared | |
| 2670 | + } else { | |
| 2671 | + $prepared_sql = $sql; // No need for placeholders. | |
| 2672 | + } | |
| 2673 | + | |
| 2674 | + $results = $wpdb->get_results( $prepared_sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared | |
| 2675 | + // Cache the results in the object cache for future use. | |
| 2676 | + wp_cache_set( $cache_key, $results, 'shopbuilder' ); // Adjust the expiration time as needed. | |
| 2677 | + Cache::set_data_cache_key( $cache_key ); | |
| 2229 | 2678 | } |
| 2230 | 2679 | |
| 2231 | - $results = $wpdb->get_results( $prepared_sql ); | |
| 2680 | + $cats = []; | |
| 2681 | + if ( ! is_array( $results ) && ! count( $results ) ) { | |
| 2682 | + return $cats; | |
| 2683 | + } | |
| 2684 | + foreach ( $results as $row ) { | |
| 2685 | + $category_id = $row->term_id; | |
| 2686 | + $category_title = $row->name; | |
| 2232 | 2687 | |
| 2688 | + $cats[] = [ | |
| 2689 | + 'value' => $category_id, | |
| 2690 | + 'label' => $category_title, | |
| 2691 | + ]; | |
| 2692 | + } | |
| 2693 | + | |
| 2694 | + // Cache the results in a static variable for the next call. | |
| 2695 | + self::$cache[ $cache_key ] = $cats; | |
| 2696 | + return $cats; | |
| 2697 | + } | |
| 2698 | + /** | |
| 2699 | + * Get WooCommerce product categories. | |
| 2700 | + * | |
| 2701 | + * @param string|null $search_query The search string for category names. | |
| 2702 | + * | |
| 2703 | + * @return array An array of product categories with 'value' and 'label' keys. | |
| 2704 | + */ | |
| 2705 | + public static function products_tags_query( $search_query = null ) { | |
| 2706 | + if ( ! is_admin() ) { | |
| 2707 | + return []; | |
| 2708 | + } | |
| 2709 | + | |
| 2710 | + $cache_key = 'rtsb_product_tags_' . md5( serialize( $search_query ) ); | |
| 2711 | + | |
| 2712 | + if ( isset( self::$cache[ $cache_key ] ) ) { | |
| 2713 | + return self::$cache[ $cache_key ]; | |
| 2714 | + } | |
| 2715 | + $results = wp_cache_get( $cache_key, 'shopbuilder' ); | |
| 2716 | + if ( ! $results ) { | |
| 2717 | + global $wpdb; | |
| 2718 | + $sql = "SELECT t.term_id, t.name | |
| 2719 | + FROM {$wpdb->terms} t | |
| 2720 | + JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id | |
| 2721 | + WHERE tt.taxonomy = 'product_tag'"; | |
| 2722 | + | |
| 2723 | + if ( $search_query ) { | |
| 2724 | + $sql .= ' AND t.name LIKE %s'; | |
| 2725 | + $prepared_sql = $wpdb->prepare( $sql, '%' . $wpdb->esc_like( $search_query ) . '%' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared | |
| 2726 | + } else { | |
| 2727 | + $prepared_sql = $sql; // No need for placeholders. | |
| 2728 | + } | |
| 2729 | + | |
| 2730 | + $results = $wpdb->get_results( $prepared_sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared | |
| 2731 | + // Cache the results in the object cache for future use. | |
| 2732 | + wp_cache_set( $cache_key, $results, 'shopbuilder' ); // Adjust the expiration time as needed. | |
| 2733 | + Cache::set_data_cache_key( $cache_key ); | |
| 2734 | + } | |
| 2735 | + | |
| 2233 | 2736 | $cats = []; |
| 2234 | 2737 | if ( ! is_array( $results ) && ! count( $results ) ) { |
| 2235 | 2738 | return $cats; |
| 2236 | 2739 | } |
| @@ -2243,18 +2746,20 @@ | ||
| 2243 | 2746 | 'label' => $category_title, |
| 2244 | 2747 | ]; |
| 2245 | 2748 | } |
| 2246 | 2749 | |
| 2750 | + // Cache the results in a static variable for the next call. | |
| 2751 | + self::$cache[ $cache_key ] = $cats; | |
| 2247 | 2752 | return $cats; |
| 2248 | 2753 | } |
| 2249 | 2754 | |
| 2250 | 2755 | /** |
| 2251 | - * @param $search_query | |
| 2756 | + * @param string $search_query Search query. | |
| 2252 | 2757 | * |
| 2253 | 2758 | * @return array |
| 2254 | 2759 | */ |
| 2255 | 2760 | public static function get_registered_post_types( $search_query = null ) { |
| 2256 | - // Get all registered post types | |
| 2761 | + // Get all registered post types. | |
| 2257 | 2762 | $registered_post_types = get_post_types( |
| 2258 | 2763 | [ |
| 2259 | 2764 | 'public' => true, |
| 2260 | 2765 | '_builtin' => false, |
| @@ -2267,11 +2772,11 @@ | ||
| 2267 | 2772 | unset( $registered_post_types['rtsb_builder'] ); |
| 2268 | 2773 | |
| 2269 | 2774 | $post_types = []; |
| 2270 | 2775 | |
| 2271 | - // Check if a search query is provided | |
| 2776 | + // Check if a search query is provided. | |
| 2272 | 2777 | if ( ! empty( $search_query ) ) { |
| 2273 | - // Filter post types based on the search query | |
| 2778 | + // Filter post types based on the search query. | |
| 2274 | 2779 | $registered_post_types = array_filter( |
| 2275 | 2780 | $registered_post_types, |
| 2276 | 2781 | function ( $post_type ) use ( $search_query ) { |
| 2277 | 2782 | return stripos( $post_type->labels->singular_name, $search_query ) !== false; |
| @@ -2276,9 +2781,9 @@ | ||
| 2276 | 2781 | function ( $post_type ) use ( $search_query ) { |
| 2277 | 2782 | return stripos( $post_type->labels->singular_name, $search_query ) !== false; |
| 2278 | 2783 | } |
| 2279 | 2784 | ); |
| 2280 | - // Check if 'post' match the search query and include them if they do | |
| 2785 | + // Check if 'post' match the search query and include them if they do. | |
| 2281 | 2786 | if ( stripos( 'post', $search_query ) !== false ) { |
| 2282 | 2787 | $post_types[] = [ |
| 2283 | 2788 | 'value' => 'post', |
| 2284 | 2789 | 'label' => 'Post', |
| @@ -2290,9 +2795,9 @@ | ||
| 2290 | 2795 | 'label' => 'Post', |
| 2291 | 2796 | ]; |
| 2292 | 2797 | } |
| 2293 | 2798 | |
| 2294 | - // Convert the filtered post types to an array | |
| 2799 | + // Convert the filtered post types to an array. | |
| 2295 | 2800 | foreach ( $registered_post_types as $post_type ) { |
| 2296 | 2801 | $post_types[] = [ |
| 2297 | 2802 | 'value' => $post_type->name, |
| 2298 | 2803 | 'label' => $post_type->labels->singular_name, |
| @@ -2304,9 +2809,9 @@ | ||
| 2304 | 2809 | |
| 2305 | 2810 | /** |
| 2306 | 2811 | * Get Post Types. |
| 2307 | 2812 | * |
| 2308 | - * @param $search_query | |
| 2813 | + * @param string $search_query Search query. | |
| 2309 | 2814 | * |
| 2310 | 2815 | * @return array |
| 2311 | 2816 | */ |
| 2312 | 2817 | public static function get_post_types( $search_query = null, $args = [] ) { |
| @@ -2317,8 +2822,9 @@ | ||
| 2317 | 2822 | 'post_type' => 'any', |
| 2318 | 2823 | 'posts_per_page' => 20, |
| 2319 | 2824 | 'orderby' => 'ID', |
| 2320 | 2825 | 'order' => 'DESC', |
| 2826 | + // 'suppress_filters' => false, // WPML Support, Remove Others Languages. | |
| 2321 | 2827 | ] |
| 2322 | 2828 | ); |
| 2323 | 2829 | |
| 2324 | 2830 | if ( 'archive' !== $args['post_type'] ) { |
| @@ -2329,11 +2835,12 @@ | ||
| 2329 | 2835 | $query_results = get_posts( $args ); |
| 2330 | 2836 | foreach ( $query_results as $post ) { |
| 2331 | 2837 | $posts[] = [ |
| 2332 | 2838 | 'value' => $post->ID, |
| 2333 | - 'label' => $post->post_title, | |
| 2839 | + 'label' => $post->post_title . ' (ID#' . $post->ID . ')', | |
| 2334 | 2840 | ]; |
| 2335 | 2841 | } |
| 2842 | + | |
| 2336 | 2843 | if ( $search_query ) { |
| 2337 | 2844 | if ( strpos( '-error 404', $search_query ) ) { |
| 2338 | 2845 | $posts[] = [ |
| 2339 | 2846 | 'value' => 'error', |
| @@ -2340,12 +2847,14 @@ | ||
| 2340 | 2847 | 'label' => __( '404 Error', 'shopbuilder' ), |
| 2341 | 2848 | ]; |
| 2342 | 2849 | } |
| 2343 | 2850 | } else { |
| 2344 | - $posts[] = [ | |
| 2345 | - 'value' => 'error', | |
| 2346 | - 'label' => __( '404 Error', 'shopbuilder' ), | |
| 2347 | - ]; | |
| 2851 | + if ( 'page' === $args['post_type'] ) { | |
| 2852 | + $posts[] = [ | |
| 2853 | + 'value' => 'error', | |
| 2854 | + 'label' => __( '404 Error', 'shopbuilder' ), | |
| 2855 | + ]; | |
| 2856 | + } | |
| 2348 | 2857 | } |
| 2349 | 2858 | } else { |
| 2350 | 2859 | $posts = self::get_registered_post_types( $search_query ); |
| 2351 | 2860 | } |
| @@ -2359,6 +2868,518 @@ | ||
| 2359 | 2868 | * @return array |
| 2360 | 2869 | */ |
| 2361 | 2870 | public static function get_elementor_breakpoints() { |
| 2362 | 2871 | return ( new \Elementor\Core\Breakpoints\Manager() )->get_breakpoints_config(); |
| 2872 | + } | |
| 2873 | + | |
| 2874 | + /** | |
| 2875 | + * Render view. | |
| 2876 | + * | |
| 2877 | + * @param string $viewName View name. | |
| 2878 | + * @param array $args View args. | |
| 2879 | + * @param boolean $return View return. | |
| 2880 | + * @return string|void | |
| 2881 | + */ | |
| 2882 | + public static function renderView( $viewName, $args = [], $return = false ) { | |
| 2883 | + $viewName = str_replace( '.', '/', $viewName ); | |
| 2884 | + | |
| 2885 | + if ( ! empty( $args ) && is_array( $args ) ) { | |
| 2886 | + extract( $args ); | |
| 2887 | + } | |
| 2888 | + | |
| 2889 | + $view_file = rtsb()->plugin_path() . '/resources/' . $viewName . '.php'; | |
| 2890 | + | |
| 2891 | + if ( ! file_exists( $view_file ) ) { | |
| 2892 | + _doing_it_wrong( __FUNCTION__, sprintf( '<code>%s</code> does not exist.', esc_html( $view_file ) ), '1.7.0' ); | |
| 2893 | + | |
| 2894 | + return; | |
| 2895 | + } | |
| 2896 | + | |
| 2897 | + if ( $return ) { | |
| 2898 | + ob_start(); | |
| 2899 | + include $view_file; | |
| 2900 | + | |
| 2901 | + return ob_get_clean(); | |
| 2902 | + } else { | |
| 2903 | + include $view_file; | |
| 2904 | + } | |
| 2905 | + } | |
| 2906 | + | |
| 2907 | + /** | |
| 2908 | + * Best selling product query. | |
| 2909 | + * | |
| 2910 | + * @param int $minimum_sale Minimum sale/ | |
| 2911 | + * @param int $limit Total limit. | |
| 2912 | + * | |
| 2913 | + * @return array|mixed | |
| 2914 | + */ | |
| 2915 | + public static function best_selling_products_ids( $minimum_sale = 1, $limit = 10 ) { | |
| 2916 | + $cache_key = 'rtsb_best_selling_products_' . $minimum_sale . '_' . $limit; | |
| 2917 | + // Check if the data is in the cache. | |
| 2918 | + if ( isset( self::$cache[ $cache_key ] ) ) { | |
| 2919 | + return self::$cache[ $cache_key ]; | |
| 2920 | + } | |
| 2921 | + $cached_data = get_transient( $cache_key ); | |
| 2922 | + if ( $cached_data ) { | |
| 2923 | + self::$cache[ $cache_key ] = $cached_data; | |
| 2924 | + return $cached_data; | |
| 2925 | + } | |
| 2926 | + global $wpdb; | |
| 2927 | + $sql = $wpdb->prepare( | |
| 2928 | + " | |
| 2929 | + SELECT ID | |
| 2930 | + FROM {$wpdb->posts} AS p | |
| 2931 | + LEFT JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id | |
| 2932 | + WHERE p.post_type = 'product' | |
| 2933 | + AND p.post_status = 'publish' | |
| 2934 | + AND pm.meta_key = 'total_sales' | |
| 2935 | + AND pm.meta_value >= %d | |
| 2936 | + ORDER BY pm.meta_value + 0 DESC | |
| 2937 | + LIMIT %d | |
| 2938 | + ", | |
| 2939 | + $minimum_sale, | |
| 2940 | + $limit | |
| 2941 | + ); | |
| 2942 | + $best_selling = $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared | |
| 2943 | + // Cache the result for future use. | |
| 2944 | + set_transient( $cache_key, $best_selling, DAY_IN_SECONDS ); | |
| 2945 | + self::$cache[ $cache_key ] = $best_selling; | |
| 2946 | + return $best_selling; | |
| 2947 | + } | |
| 2948 | + | |
| 2949 | + /** | |
| 2950 | + * @param null|Object $product Product Object. | |
| 2951 | + * @param int $days_threshold Date String. | |
| 2952 | + * | |
| 2953 | + * @return bool | |
| 2954 | + */ | |
| 2955 | + public static function is_new_product( $product = null, $days_threshold = 30 ) { | |
| 2956 | + if ( is_null( $product ) ) { | |
| 2957 | + global $product; | |
| 2958 | + } | |
| 2959 | + if ( ! $product instanceof WC_Product ) { | |
| 2960 | + return false; | |
| 2961 | + } | |
| 2962 | + | |
| 2963 | + $product_id = $product->get_id(); | |
| 2964 | + $days_threshold = ! empty( $days_threshold ) ? $days_threshold : 30; | |
| 2965 | + $cache_key = 'is_new_product_' . $product_id . '_' . $days_threshold; | |
| 2966 | + | |
| 2967 | + if ( isset( self::$cache[ $cache_key ] ) ) { | |
| 2968 | + return self::$cache[ $cache_key ]; | |
| 2969 | + } | |
| 2970 | + $date_created = $product->get_date_created(); | |
| 2971 | + if ( ! $date_created ) { | |
| 2972 | + return false; | |
| 2973 | + } | |
| 2974 | + $publish_timestamp = strtotime( $date_created->date_i18n( 'Y-m-d H:i:s' ) ); | |
| 2975 | + | |
| 2976 | + // Calculate the difference in days. | |
| 2977 | + $days_difference = abs( time() - $publish_timestamp ) / ( 60 * 60 * 24 ); | |
| 2978 | + | |
| 2979 | + // Check if the product is considered new. | |
| 2980 | + $is_new = $days_difference <= $days_threshold; | |
| 2981 | + | |
| 2982 | + // Cache the result for a day. | |
| 2983 | + self::$cache[ $cache_key ] = $is_new; | |
| 2984 | + | |
| 2985 | + return $is_new; | |
| 2986 | + } | |
| 2987 | + | |
| 2988 | + /** | |
| 2989 | + * Checks if a feature is disabled for guest users based on the provided option. | |
| 2990 | + * | |
| 2991 | + * @param string $option The option to retrieve from the item. | |
| 2992 | + * @param mixed $default The default value if the option is not found. | |
| 2993 | + * | |
| 2994 | + * @return bool | |
| 2995 | + */ | |
| 2996 | + public static function is_guest_feature_disabled( $option, $default ) { | |
| 2997 | + $disabled = self::get_option( 'general', 'guest_user', $option, $default ); | |
| 2998 | + | |
| 2999 | + return ! is_user_logged_in() && $disabled; | |
| 3000 | + } | |
| 3001 | + | |
| 3002 | + /** | |
| 3003 | + * Checks if a feature is disabled for guest users based on the provided option. | |
| 3004 | + * | |
| 3005 | + * @param string $option The option to retrieve from the item. | |
| 3006 | + * @param mixed $default The default value if the option is not found. | |
| 3007 | + * | |
| 3008 | + * @return bool | |
| 3009 | + */ | |
| 3010 | + public static function woocommerce_output_all_notices() { | |
| 3011 | + if ( function_exists( 'wc_print_notices' ) ) : | |
| 3012 | + echo '<div class="rtsb-notice">'; | |
| 3013 | + woocommerce_output_all_notices(); | |
| 3014 | + echo '</div>'; | |
| 3015 | + endif; | |
| 3016 | + } | |
| 3017 | + | |
| 3018 | + /** | |
| 3019 | + * @param object $product Product. | |
| 3020 | + * @return bool | |
| 3021 | + */ | |
| 3022 | + public static function is_visible_qty_input( $product = null ) { | |
| 3023 | + $is_visible_qty = true; | |
| 3024 | + if ( $product instanceof \WC_Product ) { | |
| 3025 | + if ( $product->is_sold_individually() ) { | |
| 3026 | + $is_visible_qty = false; | |
| 3027 | + } elseif ( $product->managing_stock() ) { | |
| 3028 | + if ( in_array( $product->get_backorders(), [ 'notify' , 'yes' ], true ) ) { | |
| 3029 | + $is_visible_qty = true; | |
| 3030 | + } elseif ( $product->get_stock_quantity() < 2 ) { | |
| 3031 | + $is_visible_qty = false; | |
| 3032 | + } | |
| 3033 | + } | |
| 3034 | + } | |
| 3035 | + return $is_visible_qty; | |
| 3036 | + } | |
| 3037 | + | |
| 3038 | + /** | |
| 3039 | + * @param int $object_id Object id. | |
| 3040 | + * @param string $element_type element type. | |
| 3041 | + * @param string|null $current_lang null for current language, default for default languages. | |
| 3042 | + * @return false|mixed|null | |
| 3043 | + */ | |
| 3044 | + public static function wpml_object_id( $object_id, $element_type, $current_lang = 'default' ) { | |
| 3045 | + if ( ! defined( 'ICL_SITEPRESS_VERSION' ) ) { | |
| 3046 | + return $object_id; | |
| 3047 | + } | |
| 3048 | + if ( ! $object_id || ! $element_type ) { | |
| 3049 | + return $object_id; | |
| 3050 | + } | |
| 3051 | + if ( 'default' === $current_lang ) { | |
| 3052 | + $lang = apply_filters( 'wpml_default_language', null ); | |
| 3053 | + } else { | |
| 3054 | + $lang = null; | |
| 3055 | + } | |
| 3056 | + return apply_filters( 'wpml_object_id', $object_id, $element_type, false, $lang ); | |
| 3057 | + } | |
| 3058 | + | |
| 3059 | + /** | |
| 3060 | + * @return string | |
| 3061 | + */ | |
| 3062 | + public static function wpml_current_language() { | |
| 3063 | + $current = apply_filters( 'wpml_current_language', null ); | |
| 3064 | + $default = apply_filters( 'wpml_default_language', null ); | |
| 3065 | + return $default !== $current ? $current : null; | |
| 3066 | + } | |
| 3067 | + | |
| 3068 | + /** | |
| 3069 | + * Custom icons. | |
| 3070 | + * | |
| 3071 | + * @return string[] | |
| 3072 | + */ | |
| 3073 | + public static function get_custom_icon_names() { | |
| 3074 | + return [ | |
| 3075 | + 'heart-empty', | |
| 3076 | + 'heart', | |
| 3077 | + 'eye', | |
| 3078 | + 'exchange', | |
| 3079 | + 'plus', | |
| 3080 | + 'minus', | |
| 3081 | + 'avatar', | |
| 3082 | + 'pay', | |
| 3083 | + 'share', | |
| 3084 | + 'clock', | |
| 3085 | + 'check-alt', | |
| 3086 | + 'check', | |
| 3087 | + 'delete', | |
| 3088 | + 'marker', | |
| 3089 | + 'list', | |
| 3090 | + 'list-2', | |
| 3091 | + 'power', | |
| 3092 | + 'cart', | |
| 3093 | + 'cart-2', | |
| 3094 | + 'cart-3', | |
| 3095 | + 'downloads', | |
| 3096 | + 'zoom', | |
| 3097 | + 'user-edit', | |
| 3098 | + 'grid', | |
| 3099 | + 'filter', | |
| 3100 | + 'billing', | |
| 3101 | + 'login', | |
| 3102 | + 'payment', | |
| 3103 | + 'search', | |
| 3104 | + 'edit', | |
| 3105 | + 'coupon', | |
| 3106 | + 'arrows-cw', | |
| 3107 | + 'trash-empty', | |
| 3108 | + ]; | |
| 3109 | + } | |
| 3110 | + | |
| 3111 | + /** | |
| 3112 | + * Retrieve an array of custom icons with their HTML representation. | |
| 3113 | + * | |
| 3114 | + * @return array | |
| 3115 | + */ | |
| 3116 | + public static function get_icons() { | |
| 3117 | + $icon = self::get_custom_icon_names(); | |
| 3118 | + $icons_array = []; | |
| 3119 | + foreach ( $icon as $value ) { | |
| 3120 | + $icons_array[ $value ] = '<i class="rtsb-icon rtsb-icon-' . $value . '"></i> <span class="icon-name">' . ucfirst( str_replace( '-', ' ', $value ) ) . '</span>'; | |
| 3121 | + } | |
| 3122 | + return $icons_array; | |
| 3123 | + } | |
| 3124 | + | |
| 3125 | + /** | |
| 3126 | + * Generates HTML markup for displaying an endpoint icon. | |
| 3127 | + * | |
| 3128 | + * @param array $data The endpoint data containing icon information. | |
| 3129 | + * @param string $endpoint The endpoint identifier. | |
| 3130 | + * @param boolean $wrapper Whether to wrap the icon in a span element. | |
| 3131 | + * | |
| 3132 | + * @return string | |
| 3133 | + */ | |
| 3134 | + public static function get_icon_html( $data, $wrapper = true ) { | |
| 3135 | + if ( empty( $data ) || 'none' === $data['icon_source'] ) { | |
| 3136 | + return ''; | |
| 3137 | + } | |
| 3138 | + $endpoint = ''; | |
| 3139 | + $html = $wrapper ? '<span class="icon ' . esc_attr( $endpoint ) . '_icon">' : ''; | |
| 3140 | + | |
| 3141 | + if ( 'select_icon' === $data['icon_source'] ) { | |
| 3142 | + $html .= '<i class="rtsb-icon rtsb-icon-' . esc_attr( $data['custom_icon'] ) . '"></i>'; | |
| 3143 | + } else { | |
| 3144 | + $icon_html = ''; | |
| 3145 | + $icon_url = $data['image_icon']['source'] ?? ''; | |
| 3146 | + $icon_id = $data['image_icon']['id'] ?? 0; | |
| 3147 | + $extension = ! empty( $icon_url ) ? strtolower( substr( strrchr( $data['image_icon']['source'], '.' ), 1 ) ) : ''; | |
| 3148 | + | |
| 3149 | + if ( 'svg' === $extension ) { | |
| 3150 | + $content = file_get_contents( $icon_url ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents | |
| 3151 | + $is_svg = strpos( $content, '<svg' ); | |
| 3152 | + | |
| 3153 | + if ( false !== $is_svg ) { | |
| 3154 | + $icon_html = substr( $content, $is_svg ); | |
| 3155 | + } | |
| 3156 | + } else { | |
| 3157 | + $attr = [ | |
| 3158 | + 'class' => 'rtsb-icon-img', | |
| 3159 | + 'alt' => esc_html( ucfirst( $endpoint ) ) . esc_html__( ' Icon', 'shopbuilder' ), | |
| 3160 | + ]; | |
| 3161 | + | |
| 3162 | + $icon_html = wp_get_attachment_image( absint( $icon_id ), 'full', true, $attr ); | |
| 3163 | + } | |
| 3164 | + | |
| 3165 | + $html .= $icon_html; | |
| 3166 | + } | |
| 3167 | + | |
| 3168 | + $html .= $wrapper ? '</span>' : ''; | |
| 3169 | + | |
| 3170 | + return $html; | |
| 3171 | + } | |
| 3172 | + /** | |
| 3173 | + * Flushes rewrite rules. | |
| 3174 | + * | |
| 3175 | + * @return void | |
| 3176 | + */ | |
| 3177 | + public static function maybe_flush_rewrite_rules() { | |
| 3178 | + add_action( 'wp_loaded', [ __CLASS__, 'flush_rewrite_rules' ] ); | |
| 3179 | + add_action( 'shutdown', [ __CLASS__, 'flush_rewrite_rules_once_more' ] ); | |
| 3180 | + } | |
| 3181 | + | |
| 3182 | + /** | |
| 3183 | + * Flushes rewrite rules if needed. | |
| 3184 | + * | |
| 3185 | + * @return void | |
| 3186 | + */ | |
| 3187 | + public static function flush_rewrite_rules() { | |
| 3188 | + if ( get_option( 'rtsb_permalinks_need_flush' ) === 'yes' ) { | |
| 3189 | + flush_rewrite_rules(); | |
| 3190 | + } | |
| 3191 | + | |
| 3192 | + if ( get_option( 'rtsb_permalinks_flushed' ) === 'yes' ) { | |
| 3193 | + flush_rewrite_rules(); | |
| 3194 | + delete_option( 'rtsb_permalinks_flushed' ); | |
| 3195 | + } | |
| 3196 | + } | |
| 3197 | + | |
| 3198 | + /** | |
| 3199 | + * Flushes rewrite rules if needed for second time. | |
| 3200 | + * | |
| 3201 | + * @return void | |
| 3202 | + */ | |
| 3203 | + public static function flush_rewrite_rules_once_more() { | |
| 3204 | + if ( get_option( 'rtsb_permalinks_need_flush' ) === 'yes' ) { | |
| 3205 | + flush_rewrite_rules(); | |
| 3206 | + update_option( 'rtsb_permalinks_flushed', 'yes' ); | |
| 3207 | + delete_option( 'rtsb_permalinks_need_flush' ); | |
| 3208 | + } | |
| 3209 | + } | |
| 3210 | + | |
| 3211 | + /** | |
| 3212 | + * Social Share Platforms. | |
| 3213 | + * | |
| 3214 | + * @return mixed|null | |
| 3215 | + */ | |
| 3216 | + public static function set_repeater_options( $section_id, $block_id, $option_key, $compare_key, $compare_value, $values ) { | |
| 3217 | + // $options = self::get_options( $section_id, $block_id ); | |
| 3218 | + $modules = DataModel::source()->get_option( $section_id, [], false ); | |
| 3219 | + if ( empty( $modules[ $block_id ] ) ) { | |
| 3220 | + return; | |
| 3221 | + } | |
| 3222 | + $options = $modules[ $block_id ]; | |
| 3223 | + if ( empty( $options[ $option_key ] ) ) { | |
| 3224 | + return; | |
| 3225 | + } | |
| 3226 | + $repeater_options = json_decode( $options[ $option_key ], true ); | |
| 3227 | + // Check if options are not empty and are in array format. | |
| 3228 | + if ( ! is_array( $repeater_options ) ) { | |
| 3229 | + return; | |
| 3230 | + } | |
| 3231 | + // Use array_column to get an array of values from $compare_key. | |
| 3232 | + $column_values = array_column( $repeater_options, $compare_key ); | |
| 3233 | + // Use array_search to find the index of the $compare_value. | |
| 3234 | + $index = array_search( $compare_value, $column_values, true ); | |
| 3235 | + if ( false === $index ) { | |
| 3236 | + return; | |
| 3237 | + } | |
| 3238 | + $repeater_options[ $index ] = wp_parse_args( $values, $repeater_options[ $index ] ); | |
| 3239 | + $options[ $option_key ] = wp_json_encode( $repeater_options ); | |
| 3240 | + $modules[ $block_id ] = $options; | |
| 3241 | + DataModel::source()->set_option( $section_id, $modules ); | |
| 3242 | + } | |
| 3243 | + | |
| 3244 | + | |
| 3245 | + /** | |
| 3246 | + * @param array $ids products id. | |
| 3247 | + * @return array | |
| 3248 | + */ | |
| 3249 | + public static function get_available_products_by_ids( $ids = [] ) { | |
| 3250 | + $ids = array_filter( | |
| 3251 | + $ids, | |
| 3252 | + function ( $id ) { | |
| 3253 | + return 'product' === get_post_type( $id ) && 'publish' === get_post_status( $id ); | |
| 3254 | + } | |
| 3255 | + ); | |
| 3256 | + return $ids; | |
| 3257 | + } | |
| 3258 | + | |
| 3259 | + /** | |
| 3260 | + * Generate and cache dynamic CSS styles. | |
| 3261 | + * | |
| 3262 | + * @param array $options CSS options to apply (e.g. padding, margin). | |
| 3263 | + * @param string $cache_key Cache key for the CSS. | |
| 3264 | + * @param array $css_properties An array of CSS properties with selectors and properties. | |
| 3265 | + * @param string $style_handle The handle for the inline styles. | |
| 3266 | + * | |
| 3267 | + * @return void | |
| 3268 | + */ | |
| 3269 | + public static function dynamic_styles( $options, $cache_key, $css_properties, $style_handle = 'rtsb-frontend' ) { | |
| 3270 | + $cached_css = wp_cache_get( $cache_key, 'shopbuilder' ); | |
| 3271 | + | |
| 3272 | + if ( false !== $cached_css ) { | |
| 3273 | + wp_add_inline_style( $style_handle, $cached_css ); | |
| 3274 | + return; | |
| 3275 | + } | |
| 3276 | + | |
| 3277 | + $css_rules = []; | |
| 3278 | + $grouped_css_rules = []; | |
| 3279 | + | |
| 3280 | + foreach ( $css_properties as $option => $details ) { | |
| 3281 | + if ( ! empty( $options[ $option ] ) ) { | |
| 3282 | + $selector = $details['selector'] ?? ''; | |
| 3283 | + $property = $details['property'] ?? ''; | |
| 3284 | + $unit = $details['unit'] ?? ''; | |
| 3285 | + $value = $options[ $option ]; | |
| 3286 | + | |
| 3287 | + if ( empty( $grouped_css_rules[ $selector ] ) ) { | |
| 3288 | + $grouped_css_rules[ $selector ] = []; | |
| 3289 | + } | |
| 3290 | + | |
| 3291 | + if ( is_array( $property ) ) { | |
| 3292 | + foreach ( $property as $prop ) { | |
| 3293 | + $grouped_css_rules[ $selector ][] = $prop . ': ' . $value . $unit . ' !important'; | |
| 3294 | + } | |
| 3295 | + } else { | |
| 3296 | + $grouped_css_rules[ $selector ][] = $property . ': ' . $value . $unit . ' !important'; | |
| 3297 | + } | |
| 3298 | + } | |
| 3299 | + } | |
| 3300 | + | |
| 3301 | + foreach ( $grouped_css_rules as $selector => $properties ) { | |
| 3302 | + $css_rules[] = $selector . ' {' . implode( '; ', $properties ) . '}'; | |
| 3303 | + } | |
| 3304 | + | |
| 3305 | + $dynamic_css = implode( ' ', $css_rules ); | |
| 3306 | + | |
| 3307 | + wp_cache_set( $cache_key, $dynamic_css, 'shopbuilder', 12 * HOUR_IN_SECONDS ); | |
| 3308 | + Cache::set_data_cache_key( $cache_key ); | |
| 3309 | + | |
| 3310 | + if ( ! empty( $dynamic_css ) ) { | |
| 3311 | + wp_add_inline_style( $style_handle, $dynamic_css ); | |
| 3312 | + } | |
| 3313 | + } | |
| 3314 | + | |
| 3315 | + /** | |
| 3316 | + * Pro version notice. | |
| 3317 | + * | |
| 3318 | + * @param string $ver Pro Version. | |
| 3319 | + * | |
| 3320 | + * @return array[] | |
| 3321 | + */ | |
| 3322 | + public static function pro_version_notice( $ver, $tab = 'billing_fields', $name = 'ShopBuilder', $enable_free_Link = true ) { | |
| 3323 | + return [ | |
| 3324 | + 'version_check' => [ | |
| 3325 | + 'id' => 'version_check', | |
| 3326 | + 'type' => 'title', | |
| 3327 | + 'label' => sprintf( | |
| 3328 | + /* translators: 1: required version, 2: link to the Plugins page */ | |
| 3329 | + esc_html__( | |
| 3330 | + 'To access all features and settings of this module, please ensure that "%1$s" is updated to version %2$s. %3$s', | |
| 3331 | + 'shopbuilder' | |
| 3332 | + ), | |
| 3333 | + $name, | |
| 3334 | + sprintf( | |
| 3335 | + '<br /><u><b>%s</b></u>', | |
| 3336 | + esc_html( $ver ?? '1.5.0' ) . ' or higher' | |
| 3337 | + ), | |
| 3338 | + $enable_free_Link | |
| 3339 | + ? sprintf( | |
| 3340 | + '%s <a class="pro-update-required" href="%s" target="_blank" title="%s">%s</a>', | |
| 3341 | + esc_attr__( 'Update to the latest version', 'shopbuilder' ), | |
| 3342 | + esc_url( admin_url( 'plugins.php' ) ), | |
| 3343 | + esc_attr__( 'Go to the Plugin Page', 'shopbuilder' ), | |
| 3344 | + esc_html__( 'from the Plugins page', 'shopbuilder' ) | |
| 3345 | + ) | |
| 3346 | + : '' | |
| 3347 | + ), | |
| 3348 | + 'tab' => $tab, | |
| 3349 | + 'customClass' => 'checkout-notice', | |
| 3350 | + ], | |
| 3351 | + ]; | |
| 3352 | + } | |
| 3353 | + | |
| 3354 | + /** | |
| 3355 | + * Get product gallery ids. | |
| 3356 | + * | |
| 3357 | + * @param object $product Product object. | |
| 3358 | + * | |
| 3359 | + * @return mixed | |
| 3360 | + */ | |
| 3361 | + public static function get_cached_gallery_ids( $product ) { | |
| 3362 | + $product_id = $product->get_id(); | |
| 3363 | + $cache_key = 'rtsb_product_gallery_ids_' . $product_id; | |
| 3364 | + | |
| 3365 | + if ( isset( self::$cache[ $cache_key ] ) ) { | |
| 3366 | + return self::$cache[ $cache_key ]; | |
| 3367 | + } | |
| 3368 | + | |
| 3369 | + $cached_result = wp_cache_get( $cache_key, 'shopbuilder' ); | |
| 3370 | + | |
| 3371 | + if ( false !== $cached_result ) { | |
| 3372 | + self::$cache[ $cache_key ] = $cached_result; | |
| 3373 | + | |
| 3374 | + return $cached_result; | |
| 3375 | + } | |
| 3376 | + | |
| 3377 | + $gallery_ids = $product->get_gallery_image_ids(); | |
| 3378 | + self::$cache[ $cache_key ] = $gallery_ids; | |
| 3379 | + | |
| 3380 | + wp_cache_set( $cache_key, $gallery_ids, 'shopbuilder', 12 * HOUR_IN_SECONDS ); | |
| 3381 | + Cache::set_data_cache_key( $cache_key ); | |
| 3382 | + | |
| 3383 | + return $gallery_ids; | |
| 2363 | 3384 | } |
| 2364 | 3385 | } |