PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.3.23
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.3.23
1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 trunk All 48 releases
fluent-cart / app / Modules / Templating / Bricks / Elements / ProductsCollection.php

ProductsCollection.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.3.23, at app/Modules/Templating/Bricks/Elements/ProductsCollection.php

416 lines 14.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Modules\Templating\Bricks\Elements;
4
5 use Bricks\Custom_Render_Element;
6 use Bricks\Helpers;
7 use Bricks\Query;
8 use FluentCart\App\Modules\Data\ProductDataSetup;
9 use FluentCart\App\Modules\Data\ProductQuery;
10 use FluentCart\App\Modules\Templating\AssetLoader;
11 use FluentCart\App\Modules\Templating\Bricks\BricksHelper;
12 use FluentCart\App\Services\Renderer\RenderHelper;
13 use FluentCart\App\Services\Renderer\ShopAppRenderer;
14 use FluentCart\Framework\Support\Arr;
15
16 if (!defined('ABSPATH')) exit; // Exit if accessed directly
17
18 class ProductsCollection extends Custom_Render_Element
19 {
20 public $category = 'fluentcart';
21 public $name = 'fct-products';
22 public $icon = 'ti-archive';
23
24 protected $cssRoot = '.fct-products-wrapper-inner .fct-products-container';
25
26 public function enqueue_scripts()
27 {
28 AssetLoader::loadProductArchiveAssets();
29 }
30
31 public function get_label()
32 {
33 return esc_html__('Products', 'fluent-cart');
34 }
35
36 public function set_control_groups()
37 {
38 $this->control_groups['query'] = [
39 'title' => esc_html__('Query', 'fluent-cart'),
40 'tab' => 'content',
41 ];
42
43 $this->control_groups['fields'] = [
44 'title' => esc_html__('Fields', 'fluent-cart'),
45 'tab' => 'content',
46 ];
47
48 $this->control_groups['widgets'] = [
49 'title' => esc_html__('Widgets', 'fluent-cart'),
50 'tab' => 'widgets',
51 ];
52 }
53
54 public function set_controls()
55 {
56 // LAYOUT
57 $this->controls['columns'] = [
58 'tab' => 'content',
59 'label' => esc_html__('Columns', 'fluent-cart'),
60 'type' => 'number',
61 'min' => 1,
62 'max' => 5,
63 'breakpoints' => true,
64 'placeholder' => 4,
65 'rerender' => true,
66 ];
67
68 $this->controls['gap'] = [
69 'tab' => 'content',
70 'label' => esc_html__('Gap', 'fluent-cart'),
71 'type' => 'number',
72 'units' => true,
73 'css' => [
74 [
75 'selector' => $this->cssRoot,
76 'property' => 'gap',
77 ],
78 ],
79 'placeholder' => 30,
80 ];
81
82 $this->controls['posts_per_page'] = [
83 'tab' => 'content',
84 'label' => esc_html__('Products per page', 'fluent-cart'),
85 'type' => 'number',
86 'min' => -1,
87 'step' => 1,
88 ];
89
90 $this->controls['is_main_query'] = [
91 'tab' => 'content',
92 'label' => esc_html__('Is main query', 'fluent-cart'),
93 'type' => 'checkbox',
94 'inline' => true,
95 ];
96
97 // QUERY
98 $this->controls['orderby'] = [
99 'tab' => 'content',
100 'label' => esc_html__('Order by', 'fluent-cart'),
101 'type' => 'select',
102 // id|date|title|price
103 'options' => [
104 'price' => esc_html__('Price', 'fluent-cart'),
105 'title' => esc_html__('Product Name', 'fluent-cart'),
106 'date' => esc_html__('Published date', 'fluent-cart'),
107 'id' => esc_html__('Product ID', 'fluent-cart')
108 ],
109 'inline' => true,
110 'placeholder' => esc_html__('Default', 'fluent-cart'),
111 ];
112
113 $this->controls['order'] = [
114 'tab' => 'content',
115 'label' => esc_html__('Order', 'fluent-cart'),
116 'type' => 'select',
117 'options' => [
118 'ASC' => esc_html__('Ascending', 'fluent-cart'),
119 'DESC' => esc_html__('Descending', 'fluent-cart'),
120 ],
121 'inline' => true,
122 'placeholder' => esc_html__('Descending', 'fluent-cart'),
123 ];
124
125 $this->controls['main_query_info'] = [
126 'tab' => 'content',
127 'group' => 'query',
128 'type' => 'info',
129 'content' => esc_html__('The query settings will be ignored when Is main query is enabled.', 'fluent-cart'),
130 ];
131
132 $this->controls['productType'] = [
133 'tab' => 'content',
134 'group' => 'query',
135 'label' => esc_html__('Product type', 'fluent-cart'),
136 'type' => 'select',
137 // physical|digital|subscription|onetime|simple|variations
138 'options' => [
139 'simple' => esc_html__('Simple', 'fluent-cart'),
140 'physical' => esc_html__('Physical', 'fluent-cart'),
141 'digital' => esc_html__('Digital', 'fluent-cart'),
142 'variations' => esc_html__('Variations', 'fluent-cart'),
143 'ontime' => esc_html__('One-time', 'fluent-cart'),
144 'subscription' => esc_html__('Subscriptions', 'fluent-cart'),
145 ],
146 'multiple' => false,
147 'placeholder' => esc_html__('all product types', 'fluent-cart'),
148 ];
149
150 $this->controls['include'] = [
151 'tab' => 'content',
152 'group' => 'query',
153 'label' => esc_html__('Include', 'fluent-cart'),
154 'type' => 'select',
155 'optionsAjax' => [
156 'action' => 'bricks_get_posts',
157 'postType' => 'fluent-products',
158 ],
159 'multiple' => true,
160 'searchable' => true,
161 'placeholder' => esc_html__('Select products', 'fluent-cart'),
162 ];
163
164 //phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude
165 $this->controls['exclude'] = [
166 'tab' => 'content',
167 'group' => 'query',
168 'label' => esc_html__('Exclude', 'fluent-cart'),
169 'type' => 'select',
170 'optionsAjax' => [
171 'action' => 'bricks_get_posts',
172 'postType' => 'fluent-products',
173 ],
174 'multiple' => true,
175 'searchable' => true,
176 'placeholder' => esc_html__('Select products', 'fluent-cart'),
177 ];
178
179 $this->controls['categories'] = [
180 'tab' => 'content',
181 'group' => 'query',
182 'label' => esc_html__('Product categories', 'fluent-cart'),
183 'type' => 'select',
184 'options' => BricksHelper::getCategoriesOptions(),
185 'multiple' => true,
186 ];
187
188 $this->controls['onSale'] = [
189 'tab' => 'content',
190 'group' => 'query',
191 'label' => esc_html__('On sale Products only', 'fluent-cart'),
192 'type' => 'checkbox',
193 ];
194
195 // $this->controls['hideOutOfStock'] = [
196 // 'tab' => 'content',
197 // 'group' => 'query',
198 // 'label' => esc_html__('Hide out of stock items', 'fluent-cart'),
199 // 'type' => 'checkbox',
200 // ];
201
202 // FIELDS
203 $fields = $this->get_post_fields();
204
205 // Remove field settings
206 unset($fields['fields']['fields']['overlay']);
207 unset($fields['fields']['fields']['dynamicPadding']);
208 unset($fields['fields']['fields']['dynamicBackground']);
209 unset($fields['fields']['fields']['dynamicBorder']);
210
211 // Set fields defaults fields set
212 $fields['fields']['default'] = [
213 [
214 'dynamicData' => '{fct_product_image:link}',
215 'id' => Helpers::generate_random_id(false),
216 ],
217 [
218 'dynamicData' => '{post_title:link}',
219 'tag' => 'h5',
220 'dynamicMargin' => [
221 'top' => 15,
222 'bottom' => 5,
223 ],
224 'id' => Helpers::generate_random_id(false),
225 ],
226 [
227 'dynamicData' => '{fct_product_price}',
228 'id' => Helpers::generate_random_id(false),
229 ],
230 [
231 'dynamicData' => '{fct_product_button}',
232 'id' => Helpers::generate_random_id(false),
233 ]
234 ];
235
236 $this->controls = array_replace_recursive($this->controls, $fields);
237
238 $this->controls['linkProduct'] = [
239 'tab' => 'content',
240 'group' => 'fields',
241 'label' => esc_html__('Link entire product', 'fluent-cart'),
242 'type' => 'checkbox',
243 'inline' => true,
244 'description' => esc_html__('Only added if none of your product fields contains any links.', 'fluent-cart'),
245 ];
246 }
247
248 public function render()
249 {
250 $settings = $this->settings;
251
252 $this->setBricksQuery();
253
254 $columns = (int)Arr::get($settings, 'columns', 4);
255 if (!$columns) {
256 $columns = 4;
257 }
258
259 if ($columns > 5) {
260 $columns = 5;
261 }
262
263 $uuid = 'fc_bx_collection_' . $this->uid;
264 if (!$this->is_frontend || !get_transient($uuid)) {
265 // save the settings as transient
266 set_transient($uuid, $settings, 48 * HOUR_IN_SECONDS);
267 }
268
269 $isMainQuery = Arr::get($settings, 'is_main_query', false) && $this->is_frontend;
270 $args = array_filter([
271 'paginate' => 'simple',
272 'is_main_query' => $isMainQuery,
273 'sort_by' => Arr::get($settings, 'orderby', 'date'),
274 'sort_type' => Arr::get($settings, 'order', 'desc'),
275 'per_page' => (int)Arr::get($settings, 'posts_per_page', 0),
276 ]);
277
278 if (!$isMainQuery) {
279 $includeIds = Arr::get($settings, 'include', []);
280 if ($includeIds) {
281 $args['include_ids'] = $includeIds;
282 }
283
284 $excludeIds = Arr::get($settings, 'exclude', []);
285 if ($excludeIds) {
286 $args['exclude_ids'] = $excludeIds;
287 }
288
289 $productType = Arr::get($settings, 'productType', []);
290 if ($productType) {
291 $args['product_type'] = $productType;
292 }
293
294 $onSale = Arr::get($settings, 'onSale', false);
295
296 if ($onSale) {
297 $args['on_sale'] = true;
298 }
299
300 $hideOutOfStock = Arr::get($settings, 'hideOutOfStock', false);
301
302 if ($hideOutOfStock) {
303 $args['stock_status'] = 'in_stock';
304 }
305
306 $categories = Arr::get($settings, 'categories', []);
307 if ($categories) {
308 //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
309 $args['tax_query'] = [
310 'product-categories' => $categories,
311 ];
312 }
313 }
314
315
316 $productsQuery = (new ProductQuery($args));
317 $products = $productsQuery->get();
318
319 $defaultFilters = $productsQuery->getDefaultFilters();
320
321 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- render_attributes() handles escaping internally
322 echo "<div {$this->render_attributes( '_root' )}>";
323
324 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- render_attributes() handles escaping internally
325 echo "<div {$this->render_attributes( 'wrapper' )}>";
326
327 $wrapperAttributes = [
328 'class' => 'fct-products-wrapper-inner mode-grid fct-full-container-width',
329 'data-fluent-cart-product-wrapper-inner' => '',
330 'data-per-page' => Arr::get($defaultFilters, 'per_page'),
331 'data-order-type' => Arr::get($defaultFilters, 'sort_type'),
332 'data-live-filter' => true,
333 'data-paginator' => 'numbers',
334 'data-default-filters' => wp_json_encode($defaultFilters)
335 ];
336
337 echo '<div class="fct-products-wrapper" data-fluent-cart-shop-app data-fluent-cart-product-wrapper>';
338 ?>
339 <div <?php RenderHelper::renderAtts($wrapperAttributes); ?>>
340 <?php
341 echo '<div data-fluent-cart-shop-app-product-list class="fct-products-container grid-columns-' . esc_attr($columns) . '">';
342 // Default WooCommerce loop template
343
344 ProductDataSetup::setProductsCache($products);
345 $postIndex = 1;
346 foreach ($products as $product) {
347 $post = get_post($product->ID);
348 setup_postdata($post);
349 $this->set_loop_object($post);
350 $this->render_fields($post, $postIndex);
351 $this->next_iteration();
352 $postIndex++;
353 }
354 wp_reset_postdata();
355
356 $this->end_iteration();
357
358 echo '</div>';
359
360 echo '</div>';
361 // Pagination print here.
362 $renderer = new ShopAppRenderer($products, [
363 'default_filters' => $defaultFilters,
364 'pagination_type' => 'simple'
365 ]);
366
367 $renderer->renderPaginator();
368 echo '</div>';
369 echo '</div>';
370 echo '</div>';
371 }
372
373 private function setBricksQuery()
374 {
375 $query_object = new Query(
376 [
377 'id' => $this->id,
378 'name' => $this->name,
379 'settings' => $this->settings,
380 ]
381 );
382
383 // Set $bricks_query (@since 1.10.2)
384 $this->set_bricks_query($query_object);
385 $this->start_iteration();
386 }
387
388 public function render_fields($post, $post_index)
389 {
390 BricksHelper::renderCollectionCard($this->settings, $post, $post_index, $this->uid);
391 }
392
393 public function renderAjaxContents($products, $settings)
394 {
395
396 $this->settings = $settings;
397
398 $this->setBricksQuery();
399
400 ProductDataSetup::setProductsCache($products);
401 $postIndex = 1;
402 foreach ($products as $product) {
403 $post = get_post($product->ID);
404 setup_postdata($post);
405 $this->set_loop_object($post);
406 $this->render_fields($post, $postIndex);
407 $this->next_iteration();
408 $postIndex++;
409 }
410 wp_reset_postdata();
411
412 $this->end_iteration();
413 }
414
415 }
416