PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.5.4
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.5.4
1.6.6 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 All 49 releases
fluent-cart / app / Modules / Templating / Bricks / Elements / ProductsCollection.php

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

772 lines 25.9 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 use FluentCart\App\Services\Renderer\ProductFilterRender;
16
17 if (!defined('ABSPATH')) exit; // Exit if accessed directly
18
19 class ProductsCollection extends Custom_Render_Element
20 {
21 public $category = 'fluent-cart';
22 public $name = 'fct-products';
23 public $icon = 'ti-archive fluent-cart-element-icon';
24
25 protected $cssRoot = '.fct-products-wrapper-inner .fct-products-container';
26
27 public function enqueue_scripts()
28 {
29 AssetLoader::loadProductArchiveAssets();
30
31 do_action('fluent_cart/advanced_variation/enqueue_assets');
32 }
33
34 public function get_label()
35 {
36 return esc_html__('Products', 'fluent-cart');
37 }
38
39 public function set_control_groups()
40 {
41 $this->control_groups['query'] = [
42 'title' => esc_html__('Query', 'fluent-cart'),
43 'tab' => 'content',
44 ];
45
46 $this->control_groups['fields'] = [
47 'title' => esc_html__('Fields', 'fluent-cart'),
48 'tab' => 'content',
49 ];
50
51 $this->control_groups['display'] = [
52 'title' => esc_html__('Display', 'fluent-cart'),
53 'tab' => 'content',
54 ];
55
56 $this->control_groups['filter'] = [
57 'title' => esc_html__('Filter', 'fluent-cart'),
58 'tab' => 'content',
59 ];
60
61 $this->control_groups['widgets'] = [
62 'title' => esc_html__('Widgets', 'fluent-cart'),
63 'tab' => 'widgets',
64 ];
65 }
66
67 public function set_controls()
68 {
69 // LAYOUT
70 $this->controls['viewMode'] = [
71 'tab' => 'content',
72 'group' => 'display',
73 'label' => esc_html__('View Mode', 'fluent-cart'),
74 'type' => 'select',
75 'options' => [
76 'grid' => esc_html__('Grid', 'fluent-cart'),
77 'list' => esc_html__('List', 'fluent-cart'),
78 ],
79 'placeholder' => esc_html__('Grid', 'fluent-cart'),
80 'rerender' => true,
81 ];
82
83 $this->controls['showViewSwitcher'] = [
84 'tab' => 'content',
85 'group' => 'display',
86 'label' => esc_html__('Show View Switcher', 'fluent-cart'),
87 'type' => 'checkbox',
88 'inline' => true,
89 'default' => true,
90 ];
91
92 $this->controls['paginationType'] = [
93 'tab' => 'content',
94 'group' => 'display',
95 'label' => esc_html__('Pagination Type', 'fluent-cart'),
96 'type' => 'select',
97 'options' => [
98 'scroll' => esc_html__('Scroll', 'fluent-cart'),
99 'numbers' => esc_html__('Numbers', 'fluent-cart'),
100 ],
101 'placeholder' => esc_html__('Numbers', 'fluent-cart'),
102 ];
103
104 $this->controls['columns'] = [
105 'tab' => 'content',
106 'label' => esc_html__('Columns', 'fluent-cart'),
107 'type' => 'number',
108 'min' => 1,
109 'max' => 5,
110 'breakpoints' => true,
111 'placeholder' => 4,
112 'css' => [
113 [
114 'selector' => $this->cssRoot,
115 'property' => '--grid-columns',
116 ],
117 ],
118 ];
119
120 $this->controls['gap'] = [
121 'tab' => 'content',
122 'label' => esc_html__('Gap', 'fluent-cart'),
123 'type' => 'number',
124 'units' => true,
125 'css' => [
126 [
127 'selector' => $this->cssRoot,
128 'property' => 'gap',
129 ],
130 ],
131 'placeholder' => 30,
132 ];
133
134 $this->controls['posts_per_page'] = [
135 'tab' => 'content',
136 'label' => esc_html__('Products per page', 'fluent-cart'),
137 'type' => 'number',
138 'min' => 1,
139 'max' => 100,
140 'placeholder' => 10,
141 'step' => 1,
142 ];
143
144 $this->controls['is_main_query'] = [
145 'tab' => 'content',
146 'label' => esc_html__('Is main query', 'fluent-cart'),
147 'type' => 'checkbox',
148 'inline' => true,
149 ];
150
151 // QUERY
152 $this->controls['orderby'] = [
153 'tab' => 'content',
154 'label' => esc_html__('Order by', 'fluent-cart'),
155 'type' => 'select',
156 // id|date|title|price
157 'options' => [
158 'price' => esc_html__('Price', 'fluent-cart'),
159 'title' => esc_html__('Product Name', 'fluent-cart'),
160 'date' => esc_html__('Published date', 'fluent-cart'),
161 'id' => esc_html__('Product ID', 'fluent-cart')
162 ],
163 'inline' => true,
164 'placeholder' => esc_html__('Default', 'fluent-cart'),
165 ];
166
167 $this->controls['order'] = [
168 'tab' => 'content',
169 'label' => esc_html__('Order', 'fluent-cart'),
170 'type' => 'select',
171 'options' => [
172 'ASC' => esc_html__('Ascending', 'fluent-cart'),
173 'DESC' => esc_html__('Descending', 'fluent-cart'),
174 ],
175 'inline' => true,
176 'placeholder' => esc_html__('Descending', 'fluent-cart'),
177 ];
178
179 $this->controls['main_query_info'] = [
180 'tab' => 'content',
181 'group' => 'query',
182 'type' => 'info',
183 'content' => esc_html__('The query settings will be ignored when Is main query is enabled.', 'fluent-cart'),
184 ];
185
186 $this->controls['productType'] = [
187 'tab' => 'content',
188 'group' => 'query',
189 'label' => esc_html__('Product type', 'fluent-cart'),
190 'type' => 'select',
191 // physical|digital|subscription|onetime|simple|variations
192 'options' => [
193 'simple' => esc_html__('Simple', 'fluent-cart'),
194 'physical' => esc_html__('Physical', 'fluent-cart'),
195 'digital' => esc_html__('Digital', 'fluent-cart'),
196 'variations' => esc_html__('Variations', 'fluent-cart'),
197 'ontime' => esc_html__('One-time', 'fluent-cart'),
198 'subscription' => esc_html__('Subscriptions', 'fluent-cart'),
199 ],
200 'multiple' => false,
201 'placeholder' => esc_html__('all product types', 'fluent-cart'),
202 ];
203
204 $this->controls['include'] = [
205 'tab' => 'content',
206 'group' => 'query',
207 'label' => esc_html__('Include', 'fluent-cart'),
208 'type' => 'select',
209 'optionsAjax' => [
210 'action' => 'bricks_get_posts',
211 'postType' => 'fluent-products',
212 ],
213 'multiple' => true,
214 'searchable' => true,
215 'placeholder' => esc_html__('Select products', 'fluent-cart'),
216 ];
217
218 //phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude
219 $this->controls['exclude'] = [
220 'tab' => 'content',
221 'group' => 'query',
222 'label' => esc_html__('Exclude', 'fluent-cart'),
223 'type' => 'select',
224 'optionsAjax' => [
225 'action' => 'bricks_get_posts',
226 'postType' => 'fluent-products',
227 ],
228 'multiple' => true,
229 'searchable' => true,
230 'placeholder' => esc_html__('Select products', 'fluent-cart'),
231 ];
232
233 $this->controls['categories'] = [
234 'tab' => 'content',
235 'group' => 'query',
236 'label' => esc_html__('Product categories', 'fluent-cart'),
237 'type' => 'select',
238 'options' => BricksHelper::getCategoriesOptions(),
239 'multiple' => true,
240 ];
241
242 $this->controls['onSale'] = [
243 'tab' => 'content',
244 'group' => 'query',
245 'label' => esc_html__('On sale Products only', 'fluent-cart'),
246 'type' => 'checkbox',
247 ];
248
249 $this->controls['allowOutOfStock'] = [
250 'tab' => 'content',
251 'group' => 'query',
252 'label' => esc_html__('Allow Out Of Stock', 'fluent-cart'),
253 'type' => 'checkbox',
254 ];
255
256 // FILTER
257 $this->controls['enableFilter'] = [
258 'tab' => 'content',
259 'group' => 'filter',
260 'label' => esc_html__('Enable Filter', 'fluent-cart'),
261 'type' => 'checkbox',
262 'inline' => true,
263 ];
264
265 $this->controls['enableSortBy'] = [
266 'tab' => 'content',
267 'group' => 'filter',
268 'label' => esc_html__('Enable Sort By', 'fluent-cart'),
269 'type' => 'checkbox',
270 'inline' => true,
271 'default' => true,
272 'required' => ['enableFilter', '=', true],
273 ];
274
275 $this->controls['liveFilter'] = [
276 'tab' => 'content',
277 'group' => 'filter',
278 'label' => esc_html__('Live Filter', 'fluent-cart'),
279 'type' => 'checkbox',
280 'inline' => true,
281 'required' => ['enableFilter', '=', true],
282 ];
283
284 $this->controls['wildcardFilter'] = [
285 'tab' => 'content',
286 'group' => 'filter',
287 'label' => esc_html__('Wildcard Filter', 'fluent-cart'),
288 'type' => 'checkbox',
289 'inline' => true,
290 'required' => ['enableFilter', '=', true],
291 ];
292
293 $this->controls['productCategories'] = [
294 'tab' => 'content',
295 'group' => 'filter',
296 'label' => esc_html__( 'Product Categories', 'fluent-cart' ),
297 'type' => 'checkbox',
298 'inline' => true,
299 'required' => ['enableFilter', '=', true],
300 ];
301
302 $this->controls['displayNameCategories'] = [
303 'tab' => 'content',
304 'group' => 'filter',
305 'label' => esc_html__('Display Name', 'fluent-cart'),
306 'type' => 'text',
307 'placeholder' => esc_html__('Custom filter label', 'fluent-cart'),
308 'required' => [
309 ['enableFilter', '=', true],
310 ['productCategories', '=', true],
311 ],
312 ];
313
314 $this->controls['productBrands'] = [
315 'tab' => 'content',
316 'group' => 'filter',
317 'label' => esc_html__( 'Product Brands', 'fluent-cart' ),
318 'type' => 'checkbox',
319 'inline' => true,
320 'required' => ['enableFilter', '=', true],
321 ];
322
323 $this->controls['displayNameBrands'] = [
324 'tab' => 'content',
325 'group' => 'filter',
326 'label' => esc_html__('Display Name', 'fluent-cart'),
327 'type' => 'text',
328 'placeholder' => esc_html__('Custom filter label', 'fluent-cart'),
329 'required' => [
330 ['enableFilter', '=', true],
331 ['productBrands', '=', true],
332 ],
333 ];
334
335 $this->controls['priceRange'] = [
336 'tab' => 'content',
337 'group' => 'filter',
338 'label' => esc_html__( 'Price Range', 'fluent-cart' ),
339 'type' => 'checkbox',
340 'inline' => true,
341 'required' => ['enableFilter', '=', true],
342 ];
343
344 $this->controls['displayNamePriceRange'] = [
345 'tab' => 'content',
346 'group' => 'filter',
347 'label' => esc_html__('Display Name', 'fluent-cart'),
348 'type' => 'text',
349 'placeholder' => esc_html__('Custom filter label', 'fluent-cart'),
350 'required' => [
351 ['enableFilter', '=', true],
352 ['priceRange', '=', true],
353 ],
354 ];
355
356 // FIELDS
357 $fields = $this->get_post_fields();
358
359 // Remove field settings
360 unset($fields['fields']['fields']['overlay']);
361 unset($fields['fields']['fields']['dynamicPadding']);
362 unset($fields['fields']['fields']['dynamicBackground']);
363 unset($fields['fields']['fields']['dynamicBorder']);
364
365 // Set fields defaults fields set
366 $fields['fields']['default'] = [
367 [
368 'dynamicData' => '{fct_product_image:link}',
369 'id' => Helpers::generate_random_id(false),
370 ],
371 [
372 'dynamicData' => '{fct_product_title:linked}',
373 'tag' => 'h5',
374 'id' => Helpers::generate_random_id(false),
375 ],
376 [
377 'dynamicData' => '{fct_product_excerpt}',
378 'tag' => 'p',
379 'id' => Helpers::generate_random_id(false),
380 ],
381 [
382 'dynamicData' => '{fct_product_price}',
383 'id' => Helpers::generate_random_id(false),
384 ],
385 [
386 'dynamicData' => '{fct_product_button}',
387 'id' => Helpers::generate_random_id(false),
388 ]
389 ];
390
391 $this->controls = array_replace_recursive($this->controls, $fields);
392
393 $this->controls['linkProduct'] = [
394 'tab' => 'content',
395 'group' => 'fields',
396 'label' => esc_html__('Link entire product', 'fluent-cart'),
397 'type' => 'checkbox',
398 'inline' => true,
399 'description' => esc_html__('Only added if none of your product fields contains any links.', 'fluent-cart'),
400 ];
401 }
402
403 public function render()
404 {
405 $settings = $this->settings;
406
407 $this->setBricksQuery();
408
409 $viewMode = Arr::get($settings, 'viewMode', 'grid');
410 $showViewSwitcher = !empty($settings['showViewSwitcher']);
411 $paginationType = Arr::get($settings, 'paginationType', 'numbers');
412 $isMainQuery = Arr::get($settings, 'is_main_query', false) && $this->is_frontend;
413 $perPage = (int)Arr::get($settings, 'posts_per_page', 10);
414 $enableFilter = !empty($settings['enableFilter']);
415 $priceRange = !empty($settings['priceRange']);
416 $liveFilter = !empty($settings['liveFilter']);
417
418 $this->storeSettingsTransient($settings);
419
420 if ($perPage <= 0) {
421 $perPage = 10;
422 }
423
424 if ($perPage > 100) {
425 $perPage = 100;
426 }
427
428 $args = $this->buildQueryArgs(
429 $settings,
430 $isMainQuery,
431 $perPage,
432 $viewMode
433 );
434
435 $productsQuery = (new ProductQuery($args));
436 $products = $productsQuery->get();
437 $defaultFilters = $productsQuery->getDefaultFilters();
438 $ajaxDefaultFilters = $this->getAjaxDefaultFilters(
439 $defaultFilters,
440 $settings
441 );
442
443 $filters = $this->getFilters($settings);
444
445 $wrapperClass = 'fct-products-wrapper-inner ' . ($viewMode === 'list' ? 'mode-list' : 'mode-grid') . (!$enableFilter ? ' fct-full-container-width' : '');
446
447 $wrapperAttributes = [
448 'class' => $wrapperClass,
449 'data-fluent-cart-product-wrapper-inner' => '',
450 'data-per-page' => $perPage,
451 'data-order-type' => Arr::get($defaultFilters, 'sort_type'),
452 'data-live-filter' => $liveFilter,
453 'data-paginator' => esc_attr($paginationType),
454 'data-default-filters' => wp_json_encode($ajaxDefaultFilters)
455 ];
456
457 $productWrapperClasses = [
458 'fct-products-wrapper',
459 'fct-brick-products-wrapper',
460 ];
461
462 if (!$this->is_frontend) {
463 $productWrapperClasses[] = 'fct-bricks-editor-mode';
464 }
465
466 $rendererConfig = [
467 'view_mode' => $viewMode,
468 'enable_wildcard_filter' => !empty($settings['wildcardFilter']),
469 'custom_filters' => [
470 'enabled' => $enableFilter,
471 'price_range' => $priceRange,
472 'live_filter' => $liveFilter
473 ],
474 ];
475
476 // Only override enable_sort_by if explicitly set in settings (key exists)
477 if (array_key_exists('enableSortBy', $settings)) {
478 $rendererConfig['enable_sort_by'] = !empty($settings['enableSortBy']);
479 }
480
481 $shopAppRenderer = new ShopAppRenderer($products, $rendererConfig);
482
483 ?>
484 <div
485 <?php
486 //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- render_attributes() handles escaping internally
487 echo $this->render_attributes('_root');
488 ?>
489 >
490 <div
491 <?php
492 //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- render_attributes() handles escaping internally
493 echo $this->render_attributes('wrapper');
494 ?>
495 >
496 <div
497 class="<?php echo esc_attr(implode(' ', $productWrapperClasses)); ?>"
498 data-fluent-cart-shop-app
499 data-fluent-cart-product-wrapper
500 >
501 <!-- View switcher -->
502 <?php
503 if ($showViewSwitcher) {
504 $shopAppRenderer->renderViewSwitcher();
505 }
506 ?>
507
508 <!-- Products Container -->
509 <div <?php RenderHelper::renderAtts($wrapperAttributes); ?>>
510 <!-- Filter render here -->
511 <?php
512 if ($enableFilter) {
513 $productFilterRenderer = new ProductFilterRender($filters);
514 $shopAppRenderer->renderFilter($productFilterRenderer);
515 }
516 ?>
517
518 <!-- Products -->
519 <div
520 data-fluent-cart-shop-app-product-list
521 class="fct-products-container"
522 >
523 <?php $this->renderProducts($products); ?>
524 </div>
525
526 <div class="fluent-cart-product-loader loader-hidden" data-fluent-cart-product-loader>
527 <div class="fluent-cart-product-spinner"></div>
528 </div>
529
530 </div>
531
532 <!-- Pagination -->
533 <?php
534 if ($paginationType !== 'scroll') {
535 $this->renderPagination(
536 $products,
537 $defaultFilters,
538 $paginationType,
539 $perPage,
540 $viewMode
541 );
542 }
543 ?>
544
545
546 </div>
547 </div>
548 </div>
549
550 <?php
551 }
552
553 /**
554 * Store settings in transient.
555 */
556 private function storeSettingsTransient($settings)
557 {
558 $uuid = 'fc_bx_collection_' . $this->uid;
559 if (!get_transient($uuid)) {
560 // save the settings as transient
561 set_transient($uuid, $settings, 48 * HOUR_IN_SECONDS);
562 }
563 }
564
565 /**
566 * Build query args.
567 */
568 private function buildQueryArgs($settings, $isMainQuery, $perPage, $viewMode) {
569 $args = array_filter([
570 'paginate' => 'simple',
571 'is_main_query' => $isMainQuery,
572 'sort_by' => Arr::get($settings, 'orderby', 'date'),
573 'sort_type' => Arr::get($settings, 'order', 'desc'),
574 'per_page' => $perPage,
575 'view_mode' => $viewMode,
576 ]);
577
578 if (!$isMainQuery) {
579 $includeIds = Arr::get($settings, 'include', []);
580 if ($includeIds) {
581 $args['include_ids'] = $includeIds;
582 }
583
584 $excludeIds = Arr::get($settings, 'exclude', []);
585 if ($excludeIds) {
586 $args['exclude_ids'] = $excludeIds;
587 }
588
589 $productType = Arr::get($settings, 'productType', []);
590 if ($productType) {
591 $args['product_type'] = $productType;
592 }
593
594 $onSale = Arr::get($settings, 'onSale', false);
595
596 if ($onSale) {
597 $args['on_sale'] = true;
598 }
599
600 $allowOutOfStock = Arr::get($settings, 'allowOutOfStock', false);
601 if ($allowOutOfStock) {
602 $args['allow_out_of_stock'] = true;
603 }
604
605 $categories = Arr::get($settings, 'categories', []);
606 if ($categories) {
607 //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
608 $args['tax_query'] = [
609 'product-categories' => $categories,
610 ];
611 }
612 }
613
614 return $args;
615 }
616
617 /**
618 * Render product loop.
619 */
620
621 private function renderProducts($products) {
622 ProductDataSetup::setProductsCache($products);
623
624 $postIndex = 1;
625
626 foreach ($products as $product) {
627 $post = get_post($product->ID);
628
629 setup_postdata($post);
630
631 $this->set_loop_object($post);
632
633 $this->render_fields($post, $postIndex);
634
635 $this->next_iteration();
636
637 $postIndex++;
638 }
639
640 wp_reset_postdata();
641
642 $this->end_iteration();
643 }
644
645 /**
646 * Render pagination.
647 */
648 private function renderPagination(
649 $products,
650 $defaultFilters,
651 $paginationType,
652 $perPage,
653 $viewMode
654 ) {
655 $renderer = new ShopAppRenderer(
656 [
657 'products' => $products,
658 'total' => $products->total(),
659 ],
660 [
661 'default_filters' => $defaultFilters,
662 'pagination_type' => $paginationType,
663 'per_page' => $perPage,
664 'view_mode' => $viewMode,
665 ]
666 );
667
668 $renderer->renderPaginator();
669 }
670
671 /**
672 * Get available product filters.
673 */
674 private function getFilters(array $settings): array
675 {
676 $categoriesLabel = !empty($settings['displayNameCategories']) ? $settings['displayNameCategories'] : __('Product Categories', 'fluent-cart');
677 $brandsLabel = !empty($settings['displayNameBrands']) ? $settings['displayNameBrands'] : __('Product Brands', 'fluent-cart');
678 $priceRangeLabel = !empty($settings['displayNamePriceRange']) ? $settings['displayNamePriceRange'] : __('Price', 'fluent-cart');
679
680 $filters = [
681 'product-categories' => [
682 'filter_type' => 'options',
683 'is_meta' => true,
684 'label' => $categoriesLabel,
685 'enabled' => !empty($settings['productCategories']),
686 'multiple' => false,
687 ],
688 'product-brands' => [
689 'filter_type' => 'options',
690 'is_meta' => true,
691 'label' => $brandsLabel,
692 'enabled' => !empty($settings['productBrands']),
693 'multiple' => false,
694 ],
695 'price_range' => [
696 'filter_type' => 'range',
697 'is_meta' => false,
698 'label' => $priceRangeLabel,
699 'enabled' => !empty($settings['priceRange'])
700 ],
701 ];
702
703 return $filters;
704 }
705
706 private function setBricksQuery()
707 {
708 $query_object = new Query(
709 [
710 'id' => $this->id,
711 'name' => $this->name,
712 'settings' => $this->settings,
713 ]
714 );
715
716 // Set $bricks_query (@since 1.10.2)
717 $this->set_bricks_query($query_object);
718 $this->start_iteration();
719 }
720
721 public function render_fields($post, $post_index)
722 {
723 BricksHelper::renderCollectionCard($this->settings, $post, $post_index, $this->uid);
724 }
725
726 public function renderAjaxContents($products, $settings)
727 {
728
729 $this->settings = $settings;
730
731 $this->setBricksQuery();
732
733 ProductDataSetup::setProductsCache($products);
734 $postIndex = 1;
735 foreach ($products as $product) {
736 $post = get_post($product->ID);
737 setup_postdata($post);
738 $this->set_loop_object($post);
739 $this->render_fields($post, $postIndex);
740 $this->next_iteration();
741 $postIndex++;
742 }
743 wp_reset_postdata();
744
745 $this->end_iteration();
746 }
747
748 private function getAjaxDefaultFilters(array $defaultFilters, array $settings): array
749 {
750 $filters = [];
751 $taxQuery = Arr::get($defaultFilters, 'tax_query', []);
752
753 if (!empty($taxQuery)) {
754 foreach ($taxQuery as $taxonomy => $termIds) {
755 $filters[$taxonomy] = $termIds;
756 }
757 }
758
759 $allowOutOfStock = Arr::get($settings, 'allowOutOfStock', false);
760 if ($allowOutOfStock) {
761 $filters['allow_out_of_stock'] = true;
762 }
763
764 if (!empty($filters)) {
765 $filters['enabled'] = true;
766 }
767
768 return $filters;
769 }
770
771 }
772