PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 2.5.2
ShopBuilder – WooCommerce Builder For Elementor v2.5.2
3.4.2 3.4.1 3.4.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 All 63 releases
← All changes | app/Helpers/Fns.php +236 -19 2.2.0 → 2.5.2 View file →
@@ -45,13 +45,12 @@
45 45 return false;
46 46 }
47 47
48 48 public static function get_nonce() {
49 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended
49 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
50 50 return isset( $_REQUEST[ rtsb()->nonceId ] ) ? sanitize_text_field( $_REQUEST[ rtsb()->nonceId ] ) : null;
51 51 }
52 52
53 -
54 53 /**
55 54 * Set Cookie or Session
56 55 *
57 56 * @param $name
@@ -75,9 +74,9 @@
75 74 public static function getSession( $name ) {
76 75 if ( ! headers_sent() && session_status() == PHP_SESSION_NONE ) {
77 76 session_start();
78 77 }
79 - return $_SESSION[ $name ] ?? null;
78 + return $_SESSION[ $name ] ?? null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
80 79 }
81 80 /**
82 81 * Remove Session Variable
83 82 *
@@ -116,8 +115,37 @@
116 115 return false;
117 116 }
118 117
119 118 /**
119 + * Get all user roles.
120 + *
121 + * @return array|false|mixed
122 + */
123 + public static function get_all_user_roles() {
124 + $cache_key = 'rtsb_get_user_roles';
125 + $roles = wp_cache_get( $cache_key, 'shopbuilder' );
126 +
127 + if ( empty( $roles ) ) {
128 + if ( ! function_exists( 'get_editable_roles' ) ) {
129 + require_once ABSPATH . 'wp-admin/includes/user.php';
130 + }
131 +
132 + $user_roles = \get_editable_roles();
133 + $roles = [];
134 +
135 + foreach ( $user_roles as $key => $role ) {
136 + if ( empty( $role['capabilities'] ) ) {
137 + continue;
138 + }
139 + $roles[ $key ] = $role['name'];
140 + }
141 + }
142 + wp_cache_set( $cache_key, $roles, 'shopbuilder' );
143 + Cache::set_data_cache_key( $cache_key );
144 + return $roles;
145 + }
146 +
147 + /**
120 148 * @param $data
121 149 *
122 150 * @return mixed|string
123 151 */
@@ -377,9 +405,9 @@
377 405 // Return the Builder Template id.
378 406
379 407 if ( get_post_type( get_the_ID() ) == BuilderFns::$post_type_tb ) {
380 408 $product_id = get_post_meta( get_the_ID(), BuilderFns::$product_template_meta, true );
381 - if ( $product_id ) {
409 + if ( $product_id && get_post_status( $product_id ) ) {
382 410 return $product_id;
383 411 }
384 412 }
385 413
@@ -429,8 +457,9 @@
429 457 *
430 458 * @return void
431 459 */
432 460 public static function doing_it_wrong( $function, $message, $version ) {
461 + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_wp_debug_backtrace_summary
433 462 $message .= ' Backtrace: ' . wp_debug_backtrace_summary();
434 463 _doing_it_wrong( esc_html( $function ), wp_kses_post( $message ), esc_html( $version ) );
435 464 }
436 465
@@ -968,13 +997,15 @@
968 997 return $allowed_html;
969 998 }
970 999
971 1000 /**
972 - * Safe print a validated HTML tag.
1001 + * Safe get a validated HTML tag.
973 1002 *
974 - * @param string $tag
1003 + * @param string $tag HTML tag.
1004 + *
1005 + * @return string
975 1006 */
976 - public static function print_validated_html_tag( $tag ) {
1007 + public static function get_validated_html_tag( $tag ) {
977 1008 $allowed_html_wrapper_tags = [
978 1009 'a',
979 1010 'article',
980 1011 'aside',
@@ -994,12 +1025,23 @@
994 1025 'section',
995 1026 'span',
996 1027 ];
997 1028
998 - self::print_html( in_array( strtolower( $tag ), $allowed_html_wrapper_tags, true ) ? $tag : 'div' );
1029 + return in_array( strtolower( $tag ), $allowed_html_wrapper_tags, true ) ? $tag : 'div';
999 1030 }
1000 1031
1001 1032 /**
1033 + * Safe print a validated HTML tag.
1034 + *
1035 + * @param string $tag HTML tag.
1036 + *
1037 + * @return void
1038 + */
1039 + public static function print_validated_html_tag( $tag ) {
1040 + self::print_html( self::get_validated_html_tag( $tag ) );
1041 + }
1042 +
1043 + /**
1002 1044 * Insert Some array element
1003 1045 *
1004 1046 * @param [type] $key The elements will insert nearby this key.
1005 1047 * @param [type] $main_array Original array.
@@ -1793,9 +1835,9 @@
1793 1835 $percentage = null;
1794 1836 $max_percentage = '';
1795 1837
1796 1838 if ( $product->is_type( 'simple' ) ) {
1797 - $max_percentage = ( ( $product->get_regular_price() - $product->get_sale_price() ) / $product->get_regular_price() ) * 100;
1839 + $max_percentage = $product->get_sale_price() ? ( ( $product->get_regular_price() - $product->get_sale_price() ) / $product->get_regular_price() ) * 100 : 0;
1798 1840 } elseif ( $product->is_type( 'variable' ) ) {
1799 1841 $max_percentage = 0;
1800 1842
1801 1843 foreach ( $product->get_children() as $child_id ) {
@@ -2150,9 +2192,9 @@
2150 2192 $link['social_action'] = 'Share';
2151 2193 break;
2152 2194 case 'reddit':
2153 2195 $link['link'] = esc_url( 'https://reddit.com/submit?url=' . $link['url'] . '&title=' . $link['title'] );
2154 - $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>';
2196 + $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>';
2155 2197 $link['attr_title'] = esc_html__( 'Share on Reddit', 'shopbuilder' );
2156 2198 $link['social_network'] = 'Reddit';
2157 2199 $link['social_action'] = 'Share';
2158 2200 break;
@@ -2307,10 +2349,14 @@
2307 2349 $the_value = [];
2308 2350 $rep_title = [];
2309 2351 if ( ! empty( $raw_value ) && is_array( $raw_value ) ) {
2310 2352 foreach ( $raw_value as $key => $value ) {
2311 - $the_value_decoded = json_decode( stripslashes_deep( $value ) );
2312 - $cr = $the_value_decoded->title ?? '';
2353 + if ( is_string( $value ) ) {
2354 + $the_value_decoded = json_decode( stripslashes_deep( $value ) );
2355 + } else {
2356 + $the_value_decoded = $value;
2357 + }
2358 + $cr = $the_value_decoded->title ?? '';
2313 2359 if ( in_array( $cr, $rep_title, true ) ) {
2314 2360 continue;
2315 2361 }
2316 2362 $rep_title[] = $cr;
@@ -2319,8 +2365,18 @@
2319 2365 } elseif ( ! empty( $raw_value ) && is_string( $raw_value ) ) {
2320 2366 $the_value = $raw_value;
2321 2367 }
2322 2368 $value = wp_json_encode( $the_value );
2369 + } elseif ( in_array( $field['type'], [ 'product_addons_special_settings', 'checkout_fields' ] ) ) {
2370 + $manual_field_value = [];
2371 + if ( is_array( $raw_value ) ) {
2372 + foreach ( $raw_value as $key => $value ) {
2373 + $manual_field_value[] = json_decode( stripslashes( $value ), true );
2374 + }
2375 + $value = wp_json_encode( $manual_field_value );
2376 + } elseif ( is_string( $raw_value ) ) {
2377 + $value = $raw_value;
2378 + }
2323 2379 } else {
2324 2380 if ( ! empty( $field['multiple'] ) || in_array( $field['type'], [ 'checkbox', 'search_and_multi_select' ] ) ) {
2325 2381 if ( isset( $raw_value ) && is_array( $raw_value ) ) {
2326 2382 if ( ! empty( $field['sanitize_fn'] ) && is_callable( $field['sanitize_fn'] ) ) {
@@ -2611,8 +2667,9 @@
2611 2667 'value' => $post->ID,
2612 2668 'label' => $post->post_title . ' ( ID ' . $post->ID . ')',
2613 2669 ];
2614 2670 }
2671 +
2615 2672 if ( $search_query ) {
2616 2673 if ( strpos( '-error 404', $search_query ) ) {
2617 2674 $posts[] = [
2618 2675 'value' => 'error',
@@ -2619,12 +2676,14 @@
2619 2676 'label' => __( '404 Error', 'shopbuilder' ),
2620 2677 ];
2621 2678 }
2622 2679 } else {
2623 - $posts[] = [
2624 - 'value' => 'error',
2625 - 'label' => __( '404 Error', 'shopbuilder' ),
2626 - ];
2680 + if ( 'page' === $args['post_type'] ) {
2681 + $posts[] = [
2682 + 'value' => 'error',
2683 + 'label' => __( '404 Error', 'shopbuilder' ),
2684 + ];
2685 + }
2627 2686 }
2628 2687 } else {
2629 2688 $posts = self::get_registered_post_types( $search_query );
2630 2689 }
@@ -2736,12 +2795,14 @@
2736 2795
2737 2796 if ( isset( self::$cache[ $cache_key ] ) ) {
2738 2797 return self::$cache[ $cache_key ];
2739 2798 }
2799 + $date_created = $product->get_date_created();
2800 + if ( ! $date_created ) {
2801 + return false;
2802 + }
2803 + $publish_timestamp = strtotime( $date_created->date_i18n( 'Y-m-d H:i:s' ) );
2740 2804
2741 - // Get the product publish date.
2742 - $publish_timestamp = strtotime( $product->get_date_created()->date_i18n( 'Y-m-d H:i:s' ) );
2743 -
2744 2805 // Calculate the difference in days.
2745 2806 $days_difference = abs( time() - $publish_timestamp ) / ( 60 * 60 * 24 );
2746 2807
2747 2808 // Check if the product is considered new.
@@ -2876,8 +2937,69 @@
2876 2937 ];
2877 2938 }
2878 2939
2879 2940 /**
2941 + * Retrieve an array of custom icons with their HTML representation.
2942 + *
2943 + * @return array
2944 + */
2945 + public static function get_icons() {
2946 + $icon = self::get_custom_icon_names();
2947 + $icons_array = [];
2948 + foreach ( $icon as $value ) {
2949 + $icons_array[ $value ] = '<i class="rtsb-icon rtsb-icon-' . $value . '"></i> <span class="icon-name">' . ucfirst( str_replace( '-', ' ', $value ) ) . '</span>';
2950 + }
2951 + return $icons_array;
2952 + }
2953 +
2954 + /**
2955 + * Generates HTML markup for displaying an endpoint icon.
2956 + *
2957 + * @param array $data The endpoint data containing icon information.
2958 + * @param string $endpoint The endpoint identifier.
2959 + * @param boolean $wrapper Whether to wrap the icon in a span element.
2960 + *
2961 + * @return string
2962 + */
2963 + public static function get_icon_html( $data, $wrapper = true ) {
2964 + if ( empty( $data ) || 'none' === $data['icon_source'] ) {
2965 + return '';
2966 + }
2967 + $endpoint = '';
2968 + $html = $wrapper ? '<span class="icon ' . esc_attr( $endpoint ) . '_icon">' : '';
2969 +
2970 + if ( 'select_icon' === $data['icon_source'] ) {
2971 + $html .= '<i class="rtsb-icon rtsb-icon-' . esc_attr( $data['custom_icon'] ) . '"></i>';
2972 + } else {
2973 + $icon_html = '';
2974 + $icon_url = $data['image_icon']['source'] ?? '';
2975 + $icon_id = $data['image_icon']['id'] ?? 0;
2976 + $extension = ! empty( $icon_url ) ? strtolower( substr( strrchr( $data['image_icon']['source'], '.' ), 1 ) ) : '';
2977 +
2978 + if ( 'svg' === $extension ) {
2979 + $content = file_get_contents( $icon_url ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
2980 + $is_svg = strpos( $content, '<svg' );
2981 +
2982 + if ( false !== $is_svg ) {
2983 + $icon_html = substr( $content, $is_svg );
2984 + }
2985 + } else {
2986 + $attr = [
2987 + 'class' => 'rtsb-icon-img',
2988 + 'alt' => esc_html( ucfirst( $endpoint ) ) . esc_html__( ' Icon', 'shopbuilder' ),
2989 + ];
2990 +
2991 + $icon_html = wp_get_attachment_image( absint( $icon_id ), 'full', true, $attr );
2992 + }
2993 +
2994 + $html .= $icon_html;
2995 + }
2996 +
2997 + $html .= $wrapper ? '</span>' : '';
2998 +
2999 + return $html;
3000 + }
3001 + /**
2880 3002 * Flushes rewrite rules.
2881 3003 *
2882 3004 * @return void
2883 3005 */
@@ -2960,6 +3082,101 @@
2960 3082 return 'product' === get_post_type( $id ) && 'publish' === get_post_status( $id );
2961 3083 }
2962 3084 );
2963 3085 return $ids;
3086 + }
3087 +
3088 + /**
3089 + * Generate and cache dynamic CSS styles.
3090 + *
3091 + * @param array $options CSS options to apply (e.g. padding, margin).
3092 + * @param string $cache_key Cache key for the CSS.
3093 + * @param array $css_properties An array of CSS properties with selectors and properties.
3094 + * @param string $style_handle The handle for the inline styles.
3095 + *
3096 + * @return void
3097 + */
3098 + public static function dynamic_styles( $options, $cache_key, $css_properties, $style_handle = 'rtsb-frontend' ) {
3099 + $cached_css = wp_cache_get( $cache_key, 'shopbuilder' );
3100 +
3101 + if ( false !== $cached_css ) {
3102 + wp_add_inline_style( $style_handle, $cached_css );
3103 + return;
3104 + }
3105 +
3106 + $css_rules = [];
3107 + $grouped_css_rules = [];
3108 +
3109 + foreach ( $css_properties as $option => $details ) {
3110 + if ( ! empty( $options[ $option ] ) ) {
3111 + $selector = $details['selector'] ?? '';
3112 + $property = $details['property'] ?? '';
3113 + $unit = $details['unit'] ?? '';
3114 + $value = $options[ $option ];
3115 +
3116 + if ( empty( $grouped_css_rules[ $selector ] ) ) {
3117 + $grouped_css_rules[ $selector ] = [];
3118 + }
3119 +
3120 + if ( is_array( $property ) ) {
3121 + foreach ( $property as $prop ) {
3122 + $grouped_css_rules[ $selector ][] = $prop . ': ' . $value . $unit . ' !important';
3123 + }
3124 + } else {
3125 + $grouped_css_rules[ $selector ][] = $property . ': ' . $value . $unit . ' !important';
3126 + }
3127 + }
3128 + }
3129 +
3130 + foreach ( $grouped_css_rules as $selector => $properties ) {
3131 + $css_rules[] = $selector . ' {' . implode( '; ', $properties ) . '}';
3132 + }
3133 +
3134 + $dynamic_css = implode( ' ', $css_rules );
3135 +
3136 + wp_cache_set( $cache_key, $dynamic_css, 'shopbuilder', 12 * HOUR_IN_SECONDS );
3137 + Cache::set_data_cache_key( $cache_key );
3138 +
3139 + if ( ! empty( $dynamic_css ) ) {
3140 + wp_add_inline_style( $style_handle, $dynamic_css );
3141 + }
3142 + }
3143 +
3144 + /**
3145 + * Pro version notice.
3146 + *
3147 + * @param string $ver Pro Version.
3148 + *
3149 + * @return array[]
3150 + */
3151 + public static function pro_version_notice( $ver, $tab = 'billing_fields', $name = 'ShopBuilder', $enable_free_Link = true ) {
3152 + return [
3153 + 'version_check' => [
3154 + 'id' => 'version_check',
3155 + 'type' => 'title',
3156 + 'label' => sprintf(
3157 + /* translators: 1: required version, 2: link to the Plugins page */
3158 + esc_html__(
3159 + 'To access all features and settings of this module, please ensure that "%1$s" is updated to version %2$s. %3$s',
3160 + 'shopbuilder'
3161 + ),
3162 + $name,
3163 + sprintf(
3164 + '<br /><u><b>%s</b></u>',
3165 + esc_html( $ver ?? '1.5.0' ) . ' or higher'
3166 + ),
3167 + $enable_free_Link
3168 + ? sprintf(
3169 + '%s <a class="pro-update-required" href="%s" target="_blank" title="%s">%s</a>',
3170 + esc_attr__( 'Update to the latest version', 'shopbuilder' ),
3171 + esc_url( admin_url( 'plugins.php' ) ),
3172 + esc_attr__( 'Go to the Plugin Page', 'shopbuilder' ),
3173 + esc_html__( 'from the Plugins page', 'shopbuilder' )
3174 + )
3175 + : ''
3176 + ),
3177 + 'tab' => $tab,
3178 + 'customClass' => 'checkout-notice',
3179 + ],
3180 + ];
2964 3181 }
2965 3182 }