PluginProbe ʕ •ᴥ•ʔ
ShopEngine Elementor WooCommerce Builder Addon – All in One WooCommerce Solution / 4.7.1
ShopEngine Elementor WooCommerce Builder Addon – All in One WooCommerce Solution v4.7.1
4.9.1 4.9.0 2.0.0 2.1.0 2.2.0 2.2.1 2.2.2 2.3.0 2.4.0 2.5.0 2.5.1 3.0.0 3.1.0 3.1.1 4.0.0 4.0.1 4.1.0 4.1.1 4.2.0 4.2.1 4.3.0 4.3.1 4.4.0 4.5.0 4.5.1 4.6.0 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.6.6 4.6.7 4.6.8 4.6.9 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.7.5 4.7.6 4.7.7 4.7.8 4.7.9 4.8.0 4.8.1 4.8.2 4.8.3 4.8.4 4.8.5 4.8.6 4.8.7 4.8.8 4.8.9 trunk 0.1.2-beta 0.1.3-beta 0.1.4-beta 1.0.0 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.2.1 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.4.0 1.4.1 1.5.0 1.5.1 1.6.0 1.6.1 1.7.0 1.8.0 1.8.1 1.9.0
shopengine / widgets / shop.php
shopengine / widgets Last commit date
add-to-cart 2 years ago additional-information 3 years ago advanced-search 3 years ago archive-description 3 years ago archive-products 1 year ago archive-result-count 2 years ago archive-title 3 years ago archive-view-mode 2 years ago breadcrumbs 4 years ago cart-table 2 years ago cart-totals 2 years ago checkout-coupon-form 3 years ago checkout-form-additional 3 years ago checkout-form-billing 2 years ago checkout-form-login 3 years ago checkout-form-shipping 2 years ago checkout-payment 3 years ago checkout-review-order 2 years ago checkout-shipping-methods 2 years ago cross-sells 1 year ago deal-products 1 year ago empty-cart-message 2 years ago filter-orderby 2 years ago filter-products-per-page 3 years ago filterable-product-list 1 year ago init 1 year ago notice 2 years ago product-categories 3 years ago product-category-lists 1 year ago product-description 2 years ago product-excerpt 3 years ago product-image 1 year ago product-list 1 year ago product-meta 2 years ago product-price 3 years ago product-rating 3 years ago product-review 2 years ago product-share 2 years ago product-sku 3 years ago product-stock 2 years ago product-tabs 2 years ago product-tags 3 years ago product-title 1 year ago recently-viewed-products 1 year ago related 1 year ago return-to-shop 2 years ago up-sells 2 years ago view-single-product 3 years ago lazy-cache.php 3 years ago manifest.php 3 years ago prod-short-code.php 2 years ago products.php 3 years ago shop.php 3 years ago widget-helper.php 2 years ago
shop.php
320 lines
1 <?php
2
3 namespace ShopEngine\Widgets;
4
5 defined('ABSPATH') || exit;
6
7 class Shop extends \WC_Shortcode_Products {
8
9 private static $_instance = null;
10 private $settings = array();
11 private $is_added_product_filter = false;
12
13
14 public function __construct($settings = array(), $type = 'products') {
15
16 $this->settings = $settings;
17 $this->type = $type;
18
19 $this->attributes = $this->parse_attributes([
20 'columns' => $settings['columns'],
21 'rows' => $settings['rows'],
22 'paginate' => $settings['paginate'],
23 'class' => $settings['class'],
24 'cache' => false,
25 ]);
26
27 $this->query_args = $this->parse_query_args();
28 }
29
30
31 protected function get_query_results() {
32
33 $results = parent::get_query_results();
34 // Start edit.
35 if($this->is_added_product_filter) {
36 remove_action('pre_get_posts', [wc()->query, 'product_query']);
37 }
38
39 // End edit.
40
41 return $results;
42 }
43
44
45 protected function parse_query_args() {
46 $settings = $this->settings;
47 $query_args = [
48 'post_type' => 'product',
49 'post_status' => 'publish',
50 'ignore_sticky_posts' => true,
51 'no_found_rows' => false === wc_string_to_bool($this->attributes['paginate']),
52 ];
53
54 if('preview' == $this->settings['query_post_type']) {
55 $query_args = $GLOBALS['wp_query']->query_vars;
56
57 // Fix for parent::get_transient_name.
58 $query_args['p'] = 0;
59 $query_args['post_type'] = 'product';
60 $query_args['post_status'] = 'publish';
61 $query_args['ignore_sticky_posts'] = true;
62 $query_args['no_found_rows'] = false === wc_string_to_bool($this->attributes['paginate']);
63 $query_args['orderby'] = '';
64 $query_args['order'] = '';
65
66 // Allow queries to run e.g. layered nav.
67 add_action('pre_get_posts', array(wc()->query, 'product_query'));
68
69 $this->is_added_product_filter = true;
70
71 } elseif('current_query' == $this->settings['query_post_type']) {
72 if(!is_page(wc_get_page_id('shop'))) {
73 $query_args = $GLOBALS['wp_query']->query_vars;
74 }
75
76 // Fix for parent::get_transient_name.
77 if(!isset($query_args['orderby'])) {
78 $query_args['orderby'] = '';
79 $query_args['order'] = '';
80 }
81
82 add_action('pre_get_posts', [wc()->query, 'product_query']);
83 $this->is_added_product_filter = true;
84
85 } else {
86 $query_args = [
87 'post_type' => 'product',
88 'post_status' => 'publish',
89 'ignore_sticky_posts' => true,
90 'no_found_rows' => false === wc_string_to_bool($this->attributes['paginate']),
91 'orderby' => $settings['orderby'],
92 'order' => strtoupper($settings['order']),
93 ];
94
95 $query_args['meta_query'] = WC()->query->get_meta_query();
96 $query_args['tax_query'] = [];
97 // @codingStandardsIgnoreEnd
98
99 // Visibility.
100 $this->set_visibility_query_args($query_args);
101
102 // SKUs.
103 $this->set_featured_query_args($query_args);
104
105 // IDs.
106 $this->set_ids_query_args($query_args);
107
108 // Set specific types query args.
109 if(method_exists($this, "set_{$this->type}_query_args")) {
110 $this->{"set_{$this->type}_query_args"}($query_args);
111 }
112
113 // Categories.
114 $this->set_categories_query_args($query_args);
115
116 // Tags.
117 $this->set_tags_query_args($query_args);
118
119 $query_args = apply_filters('woocommerce_shortcode_products_query', $query_args, $this->attributes, $this->type);
120
121 if('yes' === $settings['paginate'] && 'yes' === $settings['allow_order']) {
122 $ordering_args = WC()->query->get_catalog_ordering_args();
123 } else {
124 $ordering_args = WC()->query->get_catalog_ordering_args($query_args['orderby'], $query_args['order']);
125 }
126
127 $query_args['orderby'] = $ordering_args['orderby'];
128 $query_args['order'] = $ordering_args['order'];
129 if($ordering_args['meta_key']) {
130 $query_args['meta_key'] = $ordering_args['meta_key'];
131 }
132
133 $query_args['posts_per_page'] = intval($settings['columns'] * $settings['rows']);
134 } // End if().
135
136 if('yes' === $settings['paginate']) {
137 //phpcs:ignore WordPress.Security.NonceVerification.Recommended -- It's a fronted user part, not possible to verify nonce here
138 $page = empty($_GET['product-page']) ? 1 : absint($_GET['product-page']);
139
140 if(1 < $page) {
141 $query_args['paged'] = $page;
142 }
143
144 if('yes' !== $settings['allow_order']) {
145 remove_action('woocommerce_before_shop_loop', 'woocommerce_catalog_ordering', 30);
146 }
147
148 if('yes' !== $settings['show_result_count']) {
149 remove_action('woocommerce_before_shop_loop', 'woocommerce_result_count', 20);
150 }
151 }
152 $query_args['posts_per_page'] = intval($settings['columns'] * $settings['rows']);
153
154 // Always query only IDs.
155 $query_args['fields'] = 'ids';
156
157 return $query_args;
158 }
159
160
161 protected function set_ids_query_args(&$query_args) {
162 switch($this->settings['query_post_type']) {
163 case 'by_id':
164 $post__in = $this->settings['query_posts_ids'];
165 break;
166 case 'sale':
167 $post__in = wc_get_product_ids_on_sale();
168 break;
169 }
170
171 if(!empty($post__in)) {
172 $query_args['post__in'] = $post__in;
173 remove_action('pre_get_posts', [wc()->query, 'product_query']);
174 }
175 }
176
177
178 protected function set_categories_query_args(&$query_args) {
179 $query_type = $this->settings['query_post_type'];
180
181 if('by_id' === $query_type || 'current_query' === $query_type) {
182 return;
183 }
184
185 if(!empty($this->settings['query_product_cat_ids'])) {
186 $query_args['tax_query'][] = [
187 'taxonomy' => 'product_cat',
188 'terms' => $this->settings['query_product_cat_ids'],
189 'field' => 'term_id',
190 ];
191 }
192 }
193
194
195 protected function set_tags_query_args(&$query_args) {
196 $query_type = $this->settings['query_post_type'];
197
198 if('by_id' === $query_type || 'current_query' === $query_type) {
199 return;
200 }
201
202 if(!empty($this->settings['query_product_tag_ids'])) {
203 $query_args['tax_query'][] = [
204 'taxonomy' => 'product_tag',
205 'terms' => $this->settings['query_product_tag_ids'],
206 'field' => 'term_id',
207 'operator' => 'IN',
208 ];
209 }
210 }
211
212
213 protected function set_featured_query_args(&$query_args) {
214 if('featured' === $this->settings['query_post_type']) {
215 $product_visibility_term_ids = wc_get_product_visibility_term_ids();
216
217 $query_args['tax_query'][] = [
218 'taxonomy' => 'product_visibility',
219 'field' => 'term_taxonomy_id',
220 'terms' => [$product_visibility_term_ids['featured']],
221 ];
222 }
223 }
224
225
226 /**
227 * Loop over found products.
228 *
229 * @since 3.2.0
230 * @return string
231 */
232 protected function product_loop() {
233 $columns = absint($this->attributes['columns']);
234 $classes = $this->get_wrapper_classes($columns);
235 $products = $this->get_query_results();
236
237 ob_start();
238
239 if($products && $products->ids) {
240 // Prime caches to reduce future queries.
241 if(is_callable('_prime_post_caches')) {
242 _prime_post_caches($products->ids);
243 }
244
245 // Setup the loop.
246 wc_setup_loop(
247 array(
248 'columns' => $columns,
249 'name' => $this->type,
250 'is_shortcode' => true,
251 'is_search' => false,
252 'is_paginated' => wc_string_to_bool($this->attributes['paginate']),
253 'total' => $products->total,
254 'total_pages' => $products->total_pages,
255 'per_page' => $products->per_page,
256 'current_page' => $products->current_page,
257 )
258 );
259
260 $original_post = $GLOBALS['post'];
261
262 do_action("woocommerce_shortcode_before_{$this->type}_loop", $this->attributes);
263
264 // Fire standard shop loop hooks when paginating results so we can show result counts and so on.
265 if(wc_string_to_bool($this->attributes['paginate'])) {
266
267 if(wc_string_to_bool($this->settings['allow_order'])) {
268 woocommerce_catalog_ordering();
269 }
270 if(wc_string_to_bool($this->settings['show_result_count'])) {
271 woocommerce_result_count();
272 }
273 }
274
275 woocommerce_product_loop_start();
276
277 if(wc_get_loop_prop('total')) {
278 foreach($products->ids as $product_id) {
279 $GLOBALS['post'] = get_post($product_id); // WPCS: override ok.
280 setup_postdata($GLOBALS['post']);
281
282 // Set custom product visibility when quering hidden products.
283 add_action('woocommerce_product_is_visible', array($this, 'set_product_as_visible'));
284
285 // Render product template.
286 wc_get_template_part('content', 'product');
287
288 // Restore product visibility.
289 remove_action('woocommerce_product_is_visible', array($this, 'set_product_as_visible'));
290 }
291 }
292
293 $GLOBALS['post'] = $original_post; // WPCS: override ok.
294 woocommerce_product_loop_end();
295
296 // Fire standard shop loop hooks when paginating results so we can show result counts and so on.
297 if(wc_string_to_bool($this->attributes['paginate'])) {
298 if($this->settings['query_post_type'] == 'preview') {
299 woocommerce_pagination();
300 } else {
301 do_action('woocommerce_after_shop_loop');
302 }
303 }
304
305 do_action("woocommerce_shortcode_after_{$this->type}_loop", $this->attributes);
306
307 wp_reset_postdata();
308 wc_reset_loop();
309 } else {
310 if($this->settings['nothing_found_message']) {
311 echo '<div class="woocommerce-info elementor-nothing-found elementor-products-nothing-found">' . esc_html($this->settings['nothing_found_message']) . '</div>';
312 } else {
313 do_action("woocommerce_shortcode_{$this->type}_loop_no_results", $this->attributes);
314 }
315 }
316
317 return '<div class="' . esc_attr(implode(' ', $classes)) . '">' . ob_get_clean() . '</div>';
318 }
319
320 }