| @@ -7,8 +7,9 @@ | ||
| 7 | 7 | use FluentCart\App\Helpers\Helper; |
| 8 | 8 | use FluentCart\App\Http\Routes\WebRoutes; |
| 9 | 9 | use FluentCart\App\Modules\Templating\AssetLoader; |
| 10 | 10 | use FluentCart\Framework\Pagination\CursorPaginator; |
| 11 | +use FluentCart\Framework\Pagination\LengthAwarePaginator; | |
| 11 | 12 | use FluentCart\Framework\Support\Arr; |
| 12 | 13 | |
| 13 | 14 | class ShopAppRenderer |
| 14 | 15 | { |
| @@ -40,10 +41,15 @@ | ||
| 40 | 41 | protected $customFilters = []; |
| 41 | 42 | |
| 42 | 43 | protected $total = 0; |
| 43 | 44 | |
| 45 | + protected $isWildcardFilterEnabled = false; | |
| 46 | + | |
| 47 | + protected $enableSortBy = true; | |
| 48 | + | |
| 44 | 49 | public function __construct($products = [], $config = []) |
| 45 | 50 | { |
| 51 | + | |
| 46 | 52 | $defaultFilters = Arr::get($config, 'default_filters', []); |
| 47 | 53 | $customFilters = Arr::get($config, 'custom_filters', []); |
| 48 | 54 | $this->customFilters = $customFilters; |
| 49 | 55 | $enableFilter = false; |
| @@ -72,10 +78,11 @@ | ||
| 72 | 78 | } else if ($this->paginator === 'cursor') { |
| 73 | 79 | $this->paginator = 'scroll'; |
| 74 | 80 | } |
| 75 | 81 | $this->productBoxGridSize = $config['product_box_grid_size'] ?? 4; |
| 82 | + $this->isWildcardFilterEnabled = Arr::get($config, 'enable_wildcard_filter', false); | |
| 83 | + $this->enableSortBy = Arr::get($config, 'enable_sort_by', true); | |
| 76 | 84 | |
| 77 | - | |
| 78 | 85 | if (Arr::get($products, 'products', [])) { |
| 79 | 86 | $this->products = Arr::get($products, 'products', []); |
| 80 | 87 | } else { |
| 81 | 88 | $this->products = $products; |
| @@ -84,8 +91,15 @@ | ||
| 84 | 91 | if($this->products instanceof CursorPaginator){ |
| 85 | 92 | $this->total = 0; |
| 86 | 93 | }else{ |
| 87 | 94 | $this->total = Arr::get($products, 'total', 0); |
| 95 | + if (!$this->total && $this->products instanceof LengthAwarePaginator) { | |
| 96 | + // A raw LengthAwarePaginator's ArrayAccess proxies to its item | |
| 97 | + // collection, not its own properties, so Arr::get($products, 'total') | |
| 98 | + // above always misses when the caller passes the paginator directly | |
| 99 | + // instead of the normalized ['products' => ..., 'total' => ...] shape. | |
| 100 | + $this->total = $this->products->total(); | |
| 101 | + } | |
| 88 | 102 | } |
| 89 | 103 | //$this->total = $products['total']; |
| 90 | 104 | |
| 91 | 105 | |
| @@ -116,8 +130,17 @@ | ||
| 116 | 130 | if (Arr::get($config, 'allow_out_of_stock')) { |
| 117 | 131 | $this->defaultFilters['allow_out_of_stock'] = true; |
| 118 | 132 | } |
| 119 | 133 | |
| 134 | + // Merge wildcard search preset into defaultFilters so it persists in AJAX re-fetches | |
| 135 | + $wildcard = Arr::get($defaultFilters, 'wildcard', ''); | |
| 136 | + if ($wildcard !== '') { | |
| 137 | + $this->defaultFilters['wildcard'] = $wildcard; | |
| 138 | + if (empty($this->defaultFilters['enabled'])) { | |
| 139 | + $this->defaultFilters['enabled'] = true; | |
| 140 | + } | |
| 141 | + } | |
| 142 | + | |
| 120 | 143 | // Merge sort_by from config filters into defaultFilters for AJAX persistence |
| 121 | 144 | $configFilters = Arr::get($config, 'filters', []); |
| 122 | 145 | if (is_string($configFilters)) { |
| 123 | 146 | $configFilters = json_decode($configFilters, true) ?: []; |
| @@ -129,13 +152,19 @@ | ||
| 129 | 152 | $this->defaultFilters['enabled'] = true; |
| 130 | 153 | } |
| 131 | 154 | } |
| 132 | 155 | |
| 133 | - if (Arr::get($this->customFilters, 'price_range', false)) { | |
| 156 | + $priceRange = Arr::get($this->customFilters, 'price_range', false); | |
| 157 | + if ($priceRange) { | |
| 158 | + // Accepts true (default "Price" label) or ['label' => '...'] so | |
| 159 | + // integrations can name the price filter the same way the | |
| 160 | + // taxonomies config names taxonomy filters. | |
| 134 | 161 | $this->filters['price_range'] = [ |
| 135 | 162 | "filter_type" => "range", |
| 136 | 163 | "is_meta" => false, |
| 137 | - "label" => "Price", | |
| 164 | + "label" => is_array($priceRange) && !empty($priceRange['label']) | |
| 165 | + ? $priceRange['label'] | |
| 166 | + : "Price", | |
| 138 | 167 | "enabled" => true, |
| 139 | 168 | ]; |
| 140 | 169 | } |
| 141 | 170 | |
| @@ -234,8 +263,13 @@ | ||
| 234 | 263 | } |
| 235 | 264 | if ($onSale) { |
| 236 | 265 | $wrapperAttributes['data-on-sale'] = '1'; |
| 237 | 266 | } |
| 267 | + // Persist hide_excerpt so AJAX pagination/filtering renders cards the | |
| 268 | + // same way as the initial response (Paginator.js round-trips it). | |
| 269 | + if (Arr::get($this->config, 'hide_excerpt', false)) { | |
| 270 | + $wrapperAttributes['data-hide-excerpt'] = '1'; | |
| 271 | + } | |
| 238 | 272 | ?> |
| 239 | 273 | <div class="fct-products-wrapper" data-fluent-cart-shop-app data-fluent-cart-product-wrapper role="main" aria-label="<?php esc_attr_e('Products', 'fluent-cart'); ?>"> |
| 240 | 274 | <?php $this->renderViewSwitcher(); ?> |
| 241 | 275 | <div <?php RenderHelper::renderAtts($wrapperAttributes); ?>> |
| @@ -272,9 +306,9 @@ | ||
| 272 | 306 | ?> |
| 273 | 307 | <div class="fct-shop-view-switcher-wrap"> |
| 274 | 308 | <?php $this->renderViewSwitcherButton(); ?> |
| 275 | 309 | <?php |
| 276 | - if ($this->isFilterEnabled) { | |
| 310 | + if ($this->isFilterEnabled && $this->enableSortBy) { | |
| 277 | 311 | $this->renderSortByFilter(); |
| 278 | 312 | } |
| 279 | 313 | ?> |
| 280 | 314 | </div> |
| @@ -471,9 +505,13 @@ | ||
| 471 | 505 | <div class="fluent-cart-shop-app-filter-wrapper-inner"> |
| 472 | 506 | |
| 473 | 507 | <form class="fct-shop-filter-form" data-fluent-cart-product-filter-form role="search" |
| 474 | 508 | aria-label="<?php esc_attr_e('Product filter form', 'fluent-cart'); ?>"> |
| 475 | - <?php $renderer->renderSearch(); ?> | |
| 509 | + <?php | |
| 510 | + if($this->isWildcardFilterEnabled){ | |
| 511 | + $renderer->renderSearch(); | |
| 512 | + } | |
| 513 | + ?> | |
| 476 | 514 | <?php $renderer->renderOptions(); ?> |
| 477 | 515 | <?php if (!$this->liveFilter) : ?> |
| 478 | 516 | <div class="fct-shop-filter-item"> |
| 479 | 517 | <div class="fct-shop-button-group"> |
| @@ -513,9 +551,9 @@ | ||
| 513 | 551 | if ($index === 0) { |
| 514 | 552 | $cursorAttr = Arr::get($cursor, 'cursor', ''); |
| 515 | 553 | } |
| 516 | 554 | |
| 517 | - (new \FluentCart\App\Services\Renderer\ProductCardRender($product, ['cursor' => $cursorAttr]))->render(); | |
| 555 | + (new \FluentCart\App\Services\Renderer\ProductCardRender($product, ['cursor' => $cursorAttr, 'hide_excerpt' => Arr::get($this->config, 'hide_excerpt', false)]))->render(); | |
| 518 | 556 | ?> |
| 519 | 557 | <?php } ?> |
| 520 | 558 | <?php |
| 521 | 559 | } |