PluginProbe
Ultimate Store Kit / 3.0.8
Ultimate Store Kit v3.0.8
3.0.8 3.0.9 3.1.0 3.1.2 3.1.3 3.0.7 3.0.5 3.0.4 3.0.3 3.0.2 trunk 1.5.0 1.5.1 1.5.2 1.6.1 1.6.2 1.6.3 1.6.4 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 92 releases
ultimate-store-kit / modules / shiny-grid / module.php

module.php in Ultimate Store Kit 3.0.8, at modules/shiny-grid/module.php

261 lines 10.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace UltimateStoreKit\Modules\ShinyGrid;
4
5 use UltimateStoreKit\Base\Ultimate_Store_Kit_Module_Base;
6
7 if (!defined('ABSPATH')) {
8 exit;
9 } // Exit if accessed directly
10
11 class Module extends Ultimate_Store_Kit_Module_Base {
12
13 public static function is_active() {
14 return class_exists('woocommerce');
15 }
16
17 public function get_name() {
18 return 'usk-shiny-grid';
19 }
20
21 public function get_widgets() {
22 return ['Shiny_Grid'];
23 }
24
25 public function add_product_post_class($classes) {
26 $classes[] = 'product';
27
28 return $classes;
29 }
30
31 public function add_products_post_class_filter() {
32 \add_filter('post_class', [$this, 'add_product_post_class']);
33 }
34
35 public function remove_products_post_class_filter() {
36 \remove_filter('post_class', [$this, 'add_product_post_class']);
37 }
38
39 public function register_wc_hooks() {
40 \wc()->frontend_includes();
41 }
42
43 public function load_assets() {
44 // Load WooCommerce variation scripts for product variations
45 \wp_enqueue_script('wc-add-to-cart-variation');
46
47 // Load additional scripts for quick view functionality
48 \wp_enqueue_script('prettyPhoto');
49 \wp_enqueue_style('woocommerce_prettyPhoto_css');
50 \wp_localize_script('usk-shiny-grid', 'usk_ajax_config', [
51 'ajax_url' => \admin_url('admin-ajax.php'),
52 'nonce' => \wp_create_nonce('usk_add_to_cart'),
53 ]);
54 }
55
56 public function __construct() {
57 parent::__construct();
58
59 if (!empty($_REQUEST['action']) && 'elementor' === $_REQUEST['action'] && \is_admin()) {
60 \add_action('init', [$this, 'register_wc_hooks'], 5);
61 }
62
63 // Load variation scripts and styles
64 \add_action('wp_enqueue_scripts', array($this, 'load_assets'));
65
66 /**
67 * Modal data
68 */
69 \add_action('wp_ajax_nopriv_ultimate_store_kit_wc_product_quick_view_content', [$this, 'ultimate_store_kit_wc_product_quick_view_content']);
70 \add_action('wp_ajax_ultimate_store_kit_wc_product_quick_view_content', [$this, 'ultimate_store_kit_wc_product_quick_view_content']);
71
72 \add_action('wp_ajax_usk_add_to_cart', [$this, 'usk_add_to_cart']);
73 \add_action('wp_ajax_nopriv_usk_add_to_cart', [$this, 'usk_add_to_cart']);
74
75 \add_action('ultimate_store_kit_quick_view_product_title', 'woocommerce_template_single_title');
76 \add_action('ultimate_store_kit_quick_view_product_single_rating', 'woocommerce_template_single_rating');
77 \add_action('ultimate_store_kit_quick_view_product_single_price', 'woocommerce_template_single_price');
78 \add_action('ultimate_store_kit_quick_view_product_single_excerpt', 'woocommerce_template_single_excerpt');
79 \add_action('ultimate_store_kit_quick_view_product_single_add_to_cart', 'woocommerce_template_single_add_to_cart');
80 \add_action('ultimate_store_kit_quick_view_product_single_meta', 'woocommerce_template_single_meta');
81 \add_action('ultimate_store_kit_quick_view_product_sale_flash', 'woocommerce_show_product_sale_flash');
82 \add_action('ultimate_store_kit_quick_shiny_grid_view_product_images', [$this, 'ultimate_store_kit_quick_view_product_images']);
83
84 // Get available variations AJAX
85 \add_action('wp_ajax_usk_get_available_variations', [$this, 'usk_get_available_variations']);
86 \add_action('wp_ajax_nopriv_usk_get_available_variations', [$this, 'usk_get_available_variations']);
87
88 // Filter product class
89 \add_action('woocommerce_before_shop_loop_item', [$this, 'add_products_post_class_filter']);
90 \add_action('woocommerce_after_shop_loop_item', [$this, 'remove_products_post_class_filter']);
91
92 // Quick view support
93 \add_action('wp_ajax_ultimate_store_kit_wc_product_quick_view', [$this, 'ultimate_store_kit_wc_product_quick_view_content']);
94 \add_action('wp_ajax_nopriv_ultimate_store_kit_wc_product_quick_view', [$this, 'ultimate_store_kit_wc_product_quick_view_content']);
95 }
96
97 public function ultimate_store_kit_wc_product_quick_view_content() {
98 $product_id = isset($_POST['product_id']) ? sanitize_text_field($_POST['product_id']) : '';
99 ultimate_store_kit_wc_product_quick_view_content($product_id);
100 }
101
102 public function ultimate_store_kit_quick_view_product_images() {
103 ultimate_store_kit_quick_view_product_images();
104 }
105
106
107 public function usk_add_to_cart() {
108 \check_ajax_referer('usk_add_to_cart', 'nonce');
109
110 $product_id = isset($_POST['product_id']) ? absint($_POST['product_id']) : 0;
111 $variation_id = isset($_POST['variation_id']) ? absint($_POST['variation_id']) : 0;
112 $quantity = isset($_POST['quantity']) ? absint($_POST['quantity']) : 1;
113
114 // Get product and validate
115 $product = \wc_get_product($product_id);
116 if (!$product) {
117 \wp_send_json_error(['message' => 'Product not found']);
118 return;
119 }
120
121 // Add to cart based on product type
122 try {
123 // For variable products, we need variation ID and attributes
124 if ($product->is_type('variable') && $variation_id) {
125 // Validate that the variation exists
126 $variation = \wc_get_product($variation_id);
127 if (!$variation || $variation->get_parent_id() !== $product_id) {
128 \wp_send_json_error(['message' => 'Invalid variation']);
129 return;
130 }
131
132 // Extract all variation attributes from the request
133 $variation_data = [];
134 foreach ($_POST as $key => $value) {
135 // Check if this is an attribute
136 if (strpos($key, 'attribute_') === 0) {
137 $variation_data[$key] = \sanitize_text_field($value);
138 }
139 }
140
141 // If no attributes found, try to get them from the variation
142 if (empty($variation_data)) {
143 $attributes = $variation->get_attributes();
144 if (!empty($attributes)) {
145 foreach ($attributes as $name => $value) {
146 if (!empty($value)) {
147 $variation_data['attribute_' . $name] = $value;
148 }
149 }
150 }
151 }
152
153 // Verify we have all required variation attributes
154 if (empty($variation_data)) {
155 \wp_send_json_error(['message' => 'Missing variation attributes']);
156 return;
157 }
158
159 // Add to cart with verified data
160 $cart_item_key = \WC()->cart->add_to_cart(
161 $product_id,
162 $quantity,
163 $variation_id,
164 $variation_data
165 );
166 } else {
167 // Simple product
168 $cart_item_key = \WC()->cart->add_to_cart($product_id, $quantity);
169 }
170
171 if ($cart_item_key) {
172 \do_action('woocommerce_ajax_added_to_cart', $product_id);
173
174 // Prepare fragments for cart update
175 $fragments = [];
176 \ob_start();
177 \woocommerce_mini_cart();
178 $mini_cart = \ob_get_clean();
179 $fragments['div.widget_shopping_cart_content'] = $mini_cart;
180
181 \wp_send_json([
182 'success' => true,
183 'fragments' => $fragments,
184 'cart_hash' => \WC()->cart->get_cart_hash(),
185 'message' => 'Product added to cart'
186 ]);
187 } else {
188 $cart_error = \wc_get_notices('error');
189 $error_message = 'Failed to add to cart';
190
191 if (!empty($cart_error)) {
192 \wc_clear_notices();
193 $error_message = \strip_tags($cart_error[0]['notice']);
194 }
195
196 \wp_send_json_error([
197 'message' => $error_message
198 ]);
199 }
200 } catch (\Exception $e) {
201 \wp_send_json_error([
202 'message' => $e->getMessage()
203 ]);
204 }
205
206 exit;
207 }
208
209
210 /**
211 * AJAX handler to get available variations for a product
212 */
213 public function usk_get_available_variations() {
214 if (!isset($_POST['product_id'])) {
215 \wp_send_json_error(['message' => 'Invalid product ID']);
216 return;
217 }
218
219 $product_id = \absint($_POST['product_id']);
220 $product = \wc_get_product($product_id);
221
222 if (!$product || !$product->is_type('variable')) {
223 \wp_send_json_error(['message' => 'Not a variable product']);
224 return;
225 }
226
227 // Only expose variations of products the requester is allowed to see.
228 // wc_get_product() ignores post status, so private/draft/pending products
229 // would otherwise be readable by anyone hitting this endpoint.
230 if ('publish' !== $product->get_status() && !\current_user_can('read_post', $product_id)) {
231 \wp_send_json_error(['message' => 'Product not available'], 404);
232 return;
233 }
234
235 // Never leak variation data (prices, SKUs, stock) out of a protected product.
236 if (\post_password_required($product_id)) {
237 \wp_send_json_error(['message' => 'Product not available'], 403);
238 return;
239 }
240
241 // Get all available variations
242 $available_variations = $product->get_available_variations();
243
244 // Clean up variation data to only include what's needed for attribute filtering
245 $clean_variations = [];
246 foreach ($available_variations as $variation) {
247 $clean_variations[] = [
248 'variation_id' => $variation['variation_id'],
249 'attributes' => $variation['attributes'],
250 'is_in_stock' => $variation['is_in_stock'],
251 'is_purchasable' => $variation['is_purchasable'],
252 'image' => $variation['image'],
253 'price_html' => $variation['price_html'],
254 ];
255 }
256
257 \wp_send_json_success($clean_variations);
258 exit;
259 }
260 }
261